Re: Help optimizing UnCompress for gzipped files
On 03.01.18 22:33, Steven Schveighoffer wrote: > On 1/3/18 3:28 PM, Steven Schveighoffer wrote: >> 1. The major differentiator between the C and D algorithms is the use >> of C realloc. This one thing saves the most time. I'm going to update >> iopipe so you can use it (stand by). I will also be examining how to >> simulate using realloc when not using C malloc in iopipe. I think it's >> the copying of data to the new buffer that is causing issues. > > Looking at when C realloc actually moves the data, it appears it all of > a sudden over-allocates very very large blocks, much larger than the GC > will over-allocate. This is why the GC is losing. After a certain size, > the GC doesn't allocate blocks to grow into, so we start copying on > every realloc. That a very intersting finding! If I find some time today, I will also try a pure malloc/memcpy/free solution in c and also look how many real allocs are done. Thats funny, because this means, that this whole *2 thing for growing buffers that you learn is well taken care of in libc? Or does it still mean, that you should allocate in a pattern like this, for libc's algorithm to kick in? Is there api to see how much realloc really allocated, or is it only possible by comparing pointers to see if realloc delivers a new or the old pointer? -- Christian Köstlin
Re: Gc/D_runtime prevents dangling pointers?
On Wednesday, 3 January 2018 at 22:22:06 UTC, tipdbmp wrote: x doesn't seem to be a dangling pointer, how come? What is your definition of a dangling pointer? In the shown example we have a reference to a piece of memory containing 'x', so this memory is not freed, it's used by the program. So when you access it via the pointer you get that 'x' value, everything's ok. The comment also shows misunderstanding: when you allocate a new array you don't reuse the old memory, especially when it's still used, as it is here. This is how all GC'ed languages work: as long as you have live references to data, it's not freed and not reused. This makes all those references valid and not "dangling".
Re: Error trying to build dlang.org
On Thursday, 4 January 2018 at 02:20:32 UTC, Seb wrote: On Thursday, 4 January 2018 at 01:50:47 UTC, Tony wrote: Following the instructions here on Ubuntu 16.04: https://github.com/dlang/dlang.org/blob/master/CONTRIBUTING.md I did the command make -f posix.mak html but it failed to successfully complete: --- make[1]: Leaving directory '/home/user/dlang/dmd/src' ../dmd/generated//release//dmd -c -o- -Df/home/user/dlang/dlang.org/web/spec/spec.html macros.ddoc html.ddoc dlang.org.ddoc doc.ddoc .generated/2.078.0.ddoc .generated/dblog_latest.ddoc .generated/twid_latest.ddoc spec/spec.ddoc spec/spec.dd make: ../dmd/generated//release//dmd: Command not found posix.mak:466: recipe for target '/home/user/dlang/dlang.org/web/spec/spec.html' failed make: *** [/home/user/dlang/dlang.org/web/spec/spec.html] Error 127 1) Did you clone the `dmd` repository yourself? yes 2) Is ../dmd existent? Try nuking ../dmd and doing a fresh clone of ../dmd I forgot to check, but I deleted the dlang.org directory and tried again starting from git clone and this time it appears to have worked. Guess I should have tried that first before posting.
Re: why @property cannot be pass as ref ?
On Wednesday, 3 January 2018 at 08:51:55 UTC, Simen Kjærås wrote: On Saturday, 30 December 2017 at 03:49:37 UTC, ChangLong wrote: What I am try to do is implement a unique data type. (the ownership auto moved into new handle) Have you considered std.typecons.Unique[0]? If yes, in what ways does it not cover your needs? Your example code written with Unique would be something like the below, with some additions to show off more of what it can do: import std.typecons : Unique; import std.algorithm.mutation : move; void test1(size_t i) {} void test2(ref size_t i) {} void test3(ref Unique!size_t i) {} void test4(Unique!size_t i) {} unittest { static __gshared size_t socket; auto l1 = Unique!(size_t)(&socket); assert(l1 == &socket); Unique!(size_t) l2 = void; assert(!is(typeof({ l2 = l1; // Fails to compile - cannot copy Unique. }))); move(l1, l2); // Explicit move using std.algorithm.mutation.move. assert(l1 == null); // l1 has been cleared - only one reference to the data exists. assert(l2 == &socket); // l2 has the only reference. auto l3 = l2.release; // Implicit move, not unlike your byRef call. assert(l2 == null); // l2 has been cleared - only one reference to the data exists. assert(l3 == &socket); // l3 has the only reference. assert(!is(typeof({ auto l4 = l3; // Fails to compile - cannot copy Unique. }))); test1(*l3); // Can dereference and pass the pointed-to value. test2(*l3); // Can pass reference to pointed-to value[1]. test3(l3); // Lets you pass references to Unique. assert(!is(typeof({ test4(l3); // Fails to compile - cannot copy Unique. }))); } [0]: https://dlang.org/library/std/typecons/unique.html [1]: This surprised me a little - that's a new reference to the pointed-to value, which the callee could squirrel away somewhere it shouldn't. I guess it's there for ease of use. -- Simen Thanks for explain. I need add version number and other check into the UniqueType, std.typecons : Unique is is not suit. std.algorithm.mutation : move is what I am look for. but I don't understand why this code not working since I already add void opAssign(ref This ) to UniqueType. Unique!(size_t) l1 = Unique!(size_t)(&socket); Unique!(size_t) l2 = void; l2 = l1; // assign left value into left value, Unique is not copyable because it is annotated with @disable
Re: Using iopipe to stream a gzipped file
On 1/3/18 12:03 PM, Andrew wrote: Thanks for looking into this. So it looks like the file you have is a concatenated gzip file. If I gunzip the file and recompress it, it works properly. Looking at the docs of zlib inflate [1]: " Unlike the gunzip utility and gzread() ..., inflate() will not automatically decode concatenated gzip streams. inflate() will return Z_STREAM_END at the end of the gzip stream. The state would need to be reset to continue decoding a subsequent gzip stream." So what is happening is the inflate function is returning Z_STREAM_END, and I'm considering the stream done from that return code. I'm not sure yet how to fix this. I suppose I can check if any more data exists, and then re-init and continue. I have to look up what a concatenated gzip file is. gzread isn't good for generic purposes, because it requires an actual file input (I want to support any input type, including memory data). -Steve [1] https://github.com/dlang/phobos/blob/master/etc/c/zlib.d#L874
Re: Putting function pointers / delegates into associative array.
On Thursday, 4 January 2018 at 01:40:21 UTC, Mark wrote: What I'm trying to do here is to be able to call a function based off of a key. class tester { private void delegate() [char] funcs; this() { funcs = ['a': &A, 'b': &B]; } public void callFuncs(char a) { funcs[a](); } private void A() { writeln("A"); } private void B() { writeln("B"); } }
Re: Error trying to build dlang.org
On Thursday, 4 January 2018 at 01:50:47 UTC, Tony wrote: Following the instructions here on Ubuntu 16.04: https://github.com/dlang/dlang.org/blob/master/CONTRIBUTING.md I did the command make -f posix.mak html but it failed to successfully complete: --- make[1]: Leaving directory '/home/user/dlang/dmd/src' ../dmd/generated//release//dmd -c -o- -Df/home/user/dlang/dlang.org/web/spec/spec.html macros.ddoc html.ddoc dlang.org.ddoc doc.ddoc .generated/2.078.0.ddoc .generated/dblog_latest.ddoc .generated/twid_latest.ddoc spec/spec.ddoc spec/spec.dd make: ../dmd/generated//release//dmd: Command not found posix.mak:466: recipe for target '/home/user/dlang/dlang.org/web/spec/spec.html' failed make: *** [/home/user/dlang/dlang.org/web/spec/spec.html] Error 127 1) Did you clone the `dmd` repository yourself? 2) Is ../dmd existent? Try nuking ../dmd and doing a fresh clone of ../dmd It looks strange because normally the path should be ../dmd/generated/linux/release/64/dmd so it looks like the OS and MODEL detection doesn't work. That happens in dmd/src/osmodel.mak
Error trying to build dlang.org
Following the instructions here on Ubuntu 16.04: https://github.com/dlang/dlang.org/blob/master/CONTRIBUTING.md I did the command make -f posix.mak html but it failed to successfully complete: --- make[1]: Leaving directory '/home/user/dlang/dmd/src' ../dmd/generated//release//dmd -c -o- -Df/home/user/dlang/dlang.org/web/spec/spec.html macros.ddoc html.ddoc dlang.org.ddoc doc.ddoc .generated/2.078.0.ddoc .generated/dblog_latest.ddoc .generated/twid_latest.ddoc spec/spec.ddoc spec/spec.dd make: ../dmd/generated//release//dmd: Command not found posix.mak:466: recipe for target '/home/user/dlang/dlang.org/web/spec/spec.html' failed make: *** [/home/user/dlang/dlang.org/web/spec/spec.html] Error 127
Putting function pointers / delegates into associative array.
What I'm trying to do here is to be able to call a function based off of a key. I'm not sure how to do this, I've been messing around a bit, but the compiler doesn't like what I'm doing. Im getting: test.d(20): Error: cannot implicitly convert expression &this.A of type void delegate() to void function() test.d(21): Error: cannot implicitly convert expression &this.B of type void delegate() to void function() I'm new to the idea of using delegates. Here's the code: void main() { tester t = new tester(); t.callFuncs('a'); t.callFuncs('b'); } class tester { private void delegate() [char] funcs; this() { void delegate() a; void delegate() b; a.funcptr = &A; b.funcptr = &B; this.funcs = ['a': a, 'b': b ]; } public void callFuncs(char a) { auto t = funcs[a]; t(); } private void A() { writeln("A"); } private void B() { writeln("B"); } } I'm not sure how to go about this. It would be really cool if I can use function pointer this way.. Could someone give me a bit of advice as to what to do here? I don't want to have to bust out a big case statement for this type of thing. Thanks.
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 22:52:10 UTC, Seb wrote: Which documentation are you referring to? If it's the specification, just click "edit". I know how to edit it. I just don't know how to word it so that it isn't so confusing.
Re: how do I get only static member of a class?
On 01/03/2018 03:48 PM, Marc wrote: I found no way with __traits() on std.traits. I found isStaticFunction and isStaticArray but nothing about a member. Is this by desgin? Give a class like: class C { static int a, b, c; int d; } I'd like to get a, b and c. I'm using this: __traits(allMembers, C) class C { static int a, b, c; int d; } string[] staticMembers(T)() { string[] statics; foreach (m; __traits(derivedMembers, T)) { import std.traits : hasStaticMember; static if (hasStaticMember!(T, m)) { statics ~= m; } } return statics; } void main() { pragma(msg, staticMembers!C); } Ali
Re: No modification of pointer values in safe functions?
On Wed, Jan 03, 2018 at 03:42:07PM -0700, Jonathan M Davis via Digitalmars-d-learn wrote: > On Wednesday, January 03, 2018 22:25:16 Mark via Digitalmars-d-learn wrote: [...] > > https://dlang.org/spec/function.html#safe-functions > > > > "The following operations are not allowed in safe functions: > > > > [...] > > - No modification of pointer values. > > [...]" > > Then the spec needs to be clarified. Assignment is fine but other > types of mutation are not. Here's my attempt to clarify it: https://github.com/dlang/dlang.org/pull/2050 T -- PNP = Plug 'N' Pray
how do I get only static member of a class?
I found no way with __traits() on std.traits. I found isStaticFunction and isStaticArray but nothing about a member. Is this by desgin? Give a class like: class C { static int a, b, c; int d; } I'd like to get a, b and c. I'm using this: __traits(allMembers, C)
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 21:51:07 UTC, jmh530 wrote: On Wednesday, 3 January 2018 at 18:35:21 UTC, Ali Çehreli wrote: -I is for import directives only. imports are needed to compile the importing module. All other modules still need to be compiled themselves and added to the program either as individual .o files or as libraries (e.g. .a, .lib, etc.). The method you've shown is a shorthand for "compile each to .o and add each to the program." Working as expected... :) Ali Is there any way to re-write the documentation so its clearer? I've been confused by this before as well... Which documentation are you referring to? If it's the specification, just click "edit".
Re: No modification of pointer values in safe functions?
On Wednesday, January 03, 2018 22:25:16 Mark via Digitalmars-d-learn wrote: > On Wednesday, 3 January 2018 at 22:12:01 UTC, Jonathan M Davis > > wrote: > > On Wednesday, January 03, 2018 22:02:22 Mark via > > > > Digitalmars-d-learn wrote: > >> The documentation says the modification of pointer values is > >> not allowed in safe functions. Yet the following compiles fine > >> on dmd: > >> > >> void main() @safe > >> { > >> > >> int* x = new int; > >> int* y = new int; > >> y=x; > >> > >> } > >> > >> Is this simply a compiler bug? > > > > Where are you reading that in the documentation? There's > > nothing unsafe whatsoever about assigning one pointer to > > another. > > > > Now, pointer arithmetic is unsafe, and that's forbidden in > > @safe functions. So, I suspect that you're ether > > misunderstanding the documentation and/or the documentation > > isn't clear enough. > > > > - Jonathan M Davis > > https://dlang.org/spec/function.html#safe-functions > > "The following operations are not allowed in safe functions: > > [...] > - No modification of pointer values. > [...]" Then the spec needs to be clarified. Assignment is fine but other types of mutation are not. - Jonathan M Davis
Re: No modification of pointer values in safe functions?
On Wednesday, 3 January 2018 at 22:12:01 UTC, Jonathan M Davis wrote: On Wednesday, January 03, 2018 22:02:22 Mark via Digitalmars-d-learn wrote: The documentation says the modification of pointer values is not allowed in safe functions. Yet the following compiles fine on dmd: void main() @safe { int* x = new int; int* y = new int; y=x; } Is this simply a compiler bug? Where are you reading that in the documentation? There's nothing unsafe whatsoever about assigning one pointer to another. Now, pointer arithmetic is unsafe, and that's forbidden in @safe functions. So, I suspect that you're ether misunderstanding the documentation and/or the documentation isn't clear enough. - Jonathan M Davis https://dlang.org/spec/function.html#safe-functions "The following operations are not allowed in safe functions: [...] - No modification of pointer values. [...]"
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 12:21:28 UTC, tipdbmp wrote: // C:\libs\my_module.d module my_module; void foo() {} // main.d module main; import my_module; void main() { foo(); } Running dmd with: dmd -IC:\libs main.d my_module.d I get: Error: module my_module is in file 'my_module.d' which cannot be read import path[0] = C:\libs import path[1] = path\to\dmd\D\dmd2\windows\bin\..\..\src\phobos import path[2] = path\to\dmd\D\dmd2\windows\bin\..\..\src\druntime\import As has already been mentioned, the -I is not used for command-line files. Just compiling (-c option) shows that the -I is enough for DMD to find the import file: dmd -c main.d -Ic:\libs successfully compiles main.d into main.obj To do a full compile and link of main without compiling my_module.d each time: C:\libs>dmd -lib -ofmy_module.lib my_module.d creates "my_module.lib". Then use it to link with in main.d compile/link: C:\code\d\forum>dmd main.d -Ic:\libs -Llib c:\libs\my_module OPTLINK (R) for Win32 Release 8.00.17 Copyright (C) Digital Mars 1989-2013 All rights reserved. http://www.digitalmars.com/ctg/optlink.html OPTLINK : Warning 9: Unknown Option : NOILIB main.exe is created even though there is a mysterious warning.
Re: No modification of pointer values in safe functions?
On Wed, Jan 03, 2018 at 10:02:22PM +, Mark via Digitalmars-d-learn wrote: > The documentation says the modification of pointer values is not > allowed in safe functions. Yet the following compiles fine on dmd: > > void main() @safe > { > int* x = new int; > int* y = new int; > y=x; > } > > Is this simply a compiler bug? No, this use of pointers is perfectly safe. @safe does not mean "no pointers". What is prohibited is: - casting integers into pointers: int* ptr = cast(int*) 0xdeadbeef; // not allowed in @safe *ptr = 100; // oops, overwriting arbitrary memory - arbitrary pointer arithmetic, like: int x; int* ptr = &x; ptr++; // not allowed in @safe *ptr = 100; // oops, overwriting arbitrary stack locations. - overlapping a pointer with something else in a union, like: union U { int x; int* ptr; } U u; u.x = 12345; *u.ptr = 100; // oops, overwriting arbitrary memory // Note: @safe allows *reading* u.x after assigning a pointer to // u.ptr, since you can't do anything unsafe with an int value; // you just can't get a pointer value out of the union. - casting pointers to pointers of a different type: char ch; char* p = &ch; int* ip = cast(int*) p; // not allowed in @safe *ip = 123; // oops, overwriting arbitrary stack locations - making arbitrary slices from a pointer: char[10] buf; char* p = &buf[0]; auto q = p[0 .. 100]; // not allowed in @safe q[99] = 100; // oops, overrunning end of buffer There are probably other examples, but you get the point. It's always OK to assign and dereference pointers in @safe code, because, barring a compiler bug or unrelated @system code wreaking havoc, it's not possible to get an invalid pointer value in @safe code. (The caveat is that @safe code may call @trusted code, which in turn may call @system code. So you really have to be sure that @trusted code is actually trustworthy, otherwise you *might* get an invalid pointer percolating into @safe code, and then all bets are off.) T -- Тише едешь, дальше будешь.
Gc/D_runtime prevents dangling pointers?
char * get_dangling_ptr() { char[] a; a.reserve(15); a ~= 'x'; char *x = &a[0]; auto a_initial_ptr = a.ptr; foreach (_; 0 .. 30) { a ~= 'y'; //a.assumeSafeAppend() ~= 'y'; } assert(a.ptr != a_initial_ptr, "a should've reallocated"); // trying to reuse 'a's old memory foreach (_; 0 .. 10) { char[] b; b.reserve(15); foreach (__; 0 .. 15) { b ~= 'y'; } } return x; } void main() { import std.stdio : writefln; char *x = get_dangling_ptr(); writefln("ptr: %X; value: %s", x, *x); } x doesn't seem to be a dangling pointer, how come?
Re: No modification of pointer values in safe functions?
On Wednesday, January 03, 2018 22:02:22 Mark via Digitalmars-d-learn wrote: > The documentation says the modification of pointer values is not > allowed in safe functions. Yet the following compiles fine on dmd: > > void main() @safe > { > int* x = new int; > int* y = new int; > y=x; > } > > Is this simply a compiler bug? Where are you reading that in the documentation? There's nothing unsafe whatsoever about assigning one pointer to another. Now, pointer arithmetic is unsafe, and that's forbidden in @safe functions. So, I suspect that you're ether misunderstanding the documentation and/or the documentation isn't clear enough. - Jonathan M Davis
Re: No modification of pointer values in safe functions?
On Wednesday, 3 January 2018 at 22:02:22 UTC, Mark wrote: The documentation says the modification of pointer values is not allowed in safe functions. I think that refers to like x++ rather than x=y.
No modification of pointer values in safe functions?
The documentation says the modification of pointer values is not allowed in safe functions. Yet the following compiles fine on dmd: void main() @safe { int* x = new int; int* y = new int; y=x; } Is this simply a compiler bug?
Re: How do I use ncurses library with D? are there any wrapper?
On Wed, Jan 03, 2018 at 09:04:00PM +, Adam D. Ruppe via Digitalmars-d-learn wrote: > On Wednesday, 3 January 2018 at 19:15:18 UTC, H. S. Teoh wrote: > > https://github.com/adamdruppe/arsd/blob/master/terminal.d [...] > > Depending on what you want, you could also tack on eventloop.d from > > the same repo, with an appropriate version=with_eventloop compiler > > option, and you'll get a very nice event-driven API to handle > > keystrokes, etc.. > > Note that is Linux only and I might remove support for it in a couple > years. I'm working on a new event loop design... Thanks for the heads up. I don't mind updating my code to a new event loop design, if the new design makes sense for me. What we *really* need is a standard event loop in Phobos, so that everyone can just adhere to that API instead of reinventing event loops all over the place (I've done it myself, multiple times). T -- Meat: euphemism for dead animal. -- Flora
Re: How to use the -I command line switch?
On 01/03/2018 01:42 PM, Tony wrote: > On Wednesday, 3 January 2018 at 18:35:21 UTC, Ali Çehreli wrote: >> Working as expected... :) >> > What about the error message? If -I is only for DMD finding "import ..." > files, and not files on the command line, why does DMD list what was in > the -I "where to look for import directives" when saying that it can't > find a command-line file? It says that it can't locate my_module.d and > then lists the directory that my_module.d is in. Yeah, there's definitely a problem there. It's possible that the compiler is acting like this: Because there is already my_module.d on the command line, it assumes that main's 'import my_module' must mean that file. Because there is no such file in the local directory, it errors out by using a generic error message function, which does not explain the situation well. I made that all up but I bet it's something like that. :) Ali
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 18:35:21 UTC, Ali Çehreli wrote: -I is for import directives only. imports are needed to compile the importing module. All other modules still need to be compiled themselves and added to the program either as individual .o files or as libraries (e.g. .a, .lib, etc.). The method you've shown is a shorthand for "compile each to .o and add each to the program." Working as expected... :) Ali Is there any way to re-write the documentation so its clearer? I've been confused by this before as well...
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 18:35:21 UTC, Ali Çehreli wrote: On 01/03/2018 09:10 AM, tipdbmp wrote: dmd main.d C:\libs\my_module.d That does not use the -I switch. It compiles if I specify the full path to my_module.d: dmd -IC:\libs main.d C:\libs\my_module.d I don't understand the error message though. -I is for import directives only. imports are needed to compile the importing module. All other modules still need to be compiled themselves and added to the program either as individual .o files or as libraries (e.g. .a, .lib, etc.). The method you've shown is a shorthand for "compile each to .o and add each to the program." Working as expected... :) What about the error message? If -I is only for DMD finding "import ..." files, and not files on the command line, why does DMD list what was in the -I "where to look for import directives" when saying that it can't find a command-line file? It says that it can't locate my_module.d and then lists the directory that my_module.d is in.
Re: Help optimizing UnCompress for gzipped files
On 1/3/18 3:28 PM, Steven Schveighoffer wrote: 1. The major differentiator between the C and D algorithms is the use of C realloc. This one thing saves the most time. I'm going to update iopipe so you can use it (stand by). I will also be examining how to simulate using realloc when not using C malloc in iopipe. I think it's the copying of data to the new buffer that is causing issues. Looking at when C realloc actually moves the data, it appears it all of a sudden over-allocates very very large blocks, much larger than the GC will over-allocate. This is why the GC is losing. After a certain size, the GC doesn't allocate blocks to grow into, so we start copying on every realloc. So it's not so much the performance of the copying, but the number of times copying is required that is affecting the ultimate performance. -Steve
Re: How do I use ncurses library with D? are there any wrapper?
On Wednesday, 3 January 2018 at 19:15:18 UTC, H. S. Teoh wrote: https://github.com/adamdruppe/arsd/blob/master/terminal.d indeed. some dox here http://dpldocs.info/arsd.terminal Best of all: zero dependencies, just copy terminal.d into a subdirectory called arsd, and `import arsd.terminal;` and off you go. You still need to link it in. I suggest just listing the module on the command line with the rest of your build. If you are using rdmd or dub though I think they both automatically do, but with plain dmd you are best off just listing yourself: `dmd yourfile.d terminal.d` Depending on what you want, you could also tack on eventloop.d from the same repo, with an appropriate version=with_eventloop compiler option, and you'll get a very nice event-driven API to handle keystrokes, etc.. Note that is Linux only and I might remove support for it in a couple years. I'm working on a new event loop design...
Re: Efficient way to pass struct as parameter
On 2018-01-03 08:02, Tim Hsu wrote: It needs some experiment. This is the correct answer. Never assume anything about performance before having tested it. -- /Jacob Carlborg
Re: Can I use D with the Microsoft universal windows platform?
On Wednesday, 3 January 2018 at 18:33:27 UTC, Ozan wrote: Hi Are there any use cases or libraries for using D in Microsoft's universal windows platform environment? It would be nice to have XBOX Apps build on D ;-) Regards Ozan Ethan Watson gave a talk about D and they launched their game on the Windows Universal Platform. https://www.youtube.com/watch?v=2B0-jukh4TU&list=PLPiUzTmWuo5OmRkdAgpDRUbPyFlrXGVBL&index=15
Re: Help optimizing UnCompress for gzipped files
On 1/3/18 9:42 AM, Steven Schveighoffer wrote: On 1/3/18 2:47 AM, Christian Köstlin wrote: On 02.01.18 21:13, Steven Schveighoffer wrote: Well, you don't need to use appender for that (and doing so is copying a lot of the data an extra time). All you need is to extend the pipe until there isn't any more new data, and it will all be in the buffer. // almost the same line from your current version auto mypipe = openDev("../out/nist/2011.json.gz") .bufd.unzip(CompressionFormat.gzip); // This line here will work with the current release (0.0.2): while(mypipe.extend(0) != 0) {} Thanks for this input, I updated the program to make use of this method and compare it to the appender thing as well. Hm.. the numbers are worse! I would have expected to be at least comparable. I'll have to look into it. Thanks for posting this. Alright. I have spent some time examining the issues, and here are my findings: 1. The major differentiator between the C and D algorithms is the use of C realloc. This one thing saves the most time. I'm going to update iopipe so you can use it (stand by). I will also be examining how to simulate using realloc when not using C malloc in iopipe. I think it's the copying of data to the new buffer that is causing issues. 2. extend(0) always attempts to read 8k more bytes. The buffer extends by 8k by going into another couple pages. Somehow this is choking the algorithm. I think the cost of extending pages actually ends up hurting performance (something we need to look at in the GC in general). 3. extendElems should allow extending all the elements in the most optimal fashion. Fixing that, iopipe performs as well as the Appender/iopipe version. This is coming out as well. Stay tuned, there will be updates to iopipe to hopefully make it as fast in this microbenchmark as the C version :) -Steve
Re: How do I use ncurses library with D? are there any wrapper?
On Wed, Jan 03, 2018 at 03:47:58PM +, Marc via Digitalmars-d-learn wrote: > Long time ago, IIRC, I read somewhere there was a ncurses for D but > now I can't find it are there any wrapper or am I mistaken? anyway, > I'm doing it from scratch and not porting anything so even a library > with same functionality as ncurses for D is welcome. Depending on what you want to do, this might be just the ticket: https://github.com/adamdruppe/arsd/blob/master/terminal.d I've used this for several of my CLI programs, and it works quite well, and is relatively easy to use. Best of all: zero dependencies, just copy terminal.d into a subdirectory called arsd, and `import arsd.terminal;` and off you go. Depending on what you want, you could also tack on eventloop.d from the same repo, with an appropriate version=with_eventloop compiler option, and you'll get a very nice event-driven API to handle keystrokes, etc.. T -- When solving a problem, take care that you do not become part of the problem.
Re: what's the proper way to convert wchar[] to string?
On Wednesday, 3 January 2018 at 18:59:39 UTC, Ali Çehreli wrote: On 01/03/2018 10:50 AM, Marc wrote: when calling winapi functions, usually you to deal with the result in wchar[]. How do I convert it to string in D to be usable by the application? does D have a native for this? std.conv has to and text: auto s0 = w.text; auto s1 = w.to!string; Ali whoa, that simple. I've tried to!string(w) before, but I realized the mistake I was passing the whole buffer rather: string s = w[0 .. wcslen(w.ptr)].to!string; Thanks.
Re: Efficient way to pass struct as parameter
On 01/03/2018 10:40 AM, Patrick Schluter wrote: > On Tuesday, 2 January 2018 at 23:27:22 UTC, H. S. Teoh wrote: >> >> When it comes to optimization, there are 3 rules: profile, profile, >> profile. I used to heavily hand-"optimize" my code a lot (I come from >> a strong C/C++ background -- premature optimization seems to be a >> common malady among us in that crowd). > > That's why I always tell that C++ is premature optimization oriented > programming, aka as POOP. In my earlier C++ days I've embarrassed myself by insisting that strings should be passed by reference for performance reasons. (No, I had not profiled.) Then I learned more and always returned vectors (and maps) by value from producer functions: vector makeInts(some param) { // ... } That's how it should be! :) I used the same function when interviewing candidates (apologies to all; I don't remember good things about my interviewing other people; I hope I will never interview people like that anymore). They would invariably write a function something like this: void makeInts(vector & result, some param) { // ... } And that's wrong because there are the big questions of what do you require or do with the reference parameter 'result'? Would you clear it first? If not, shouldn't the function be named appendInts? If you cleared it upfront, would you still be happy if an exception was thrown inside the function, etc. That's why I like producer functions that return values: vector makeInts(some param) { // ... } And if they can be 'pure', D allows them to be used to initialize immutable variables as well. Pretty cool! :) Ali
Re: what's the proper way to convert wchar[] to string?
On 01/03/2018 10:50 AM, Marc wrote: when calling winapi functions, usually you to deal with the result in wchar[]. How do I convert it to string in D to be usable by the application? does D have a native for this? std.conv has to and text: auto s0 = w.text; auto s1 = w.to!string; Ali
what's the proper way to convert wchar[] to string?
when calling winapi functions, usually you to deal with the result in wchar[]. How do I convert it to string in D to be usable by the application? does D have a native for this?
Re: Efficient way to pass struct as parameter
On Tuesday, 2 January 2018 at 23:27:22 UTC, H. S. Teoh wrote: When it comes to optimization, there are 3 rules: profile, profile, profile. I used to heavily hand-"optimize" my code a lot (I come from a strong C/C++ background -- premature optimization seems to be a common malady among us in that crowd). That's why I always tell that C++ is premature optimization oriented programming, aka as POOP.
Re: How to use the -I command line switch?
On 01/03/2018 09:10 AM, tipdbmp wrote: dmd main.d C:\libs\my_module.d That does not use the -I switch. It compiles if I specify the full path to my_module.d: dmd -IC:\libs main.d C:\libs\my_module.d I don't understand the error message though. -I is for import directives only. imports are needed to compile the importing module. All other modules still need to be compiled themselves and added to the program either as individual .o files or as libraries (e.g. .a, .lib, etc.). The method you've shown is a shorthand for "compile each to .o and add each to the program." Working as expected... :) Ali
Can I use D with the Microsoft universal windows platform?
Hi Are there any use cases or libraries for using D in Microsoft's universal windows platform environment? It would be nice to have XBOX Apps build on D ;-) Regards Ozan
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 17:10:22 UTC, tipdbmp wrote: dmd main.d C:\libs\my_module.d That does not use the -I switch. It compiles if I specify the full path to my_module.d: dmd -IC:\libs main.d C:\libs\my_module.d I don't understand the error message though. I tried a few other options, but I don't use it enough to know the trick to get it working. I tend to use either dub, setting the path environmental variables, or the absolute path. Hopefully someone else can let you know. If it's a bug, it should be in bugzilla, but sometimes I just assume I screwed something up.
Re: Is it bad form to put code in package.d other than imports?
On Wed, Jan 03, 2018 at 12:43:52AM -0700, Jonathan M Davis via Digitalmars-d-learn wrote: > On Wednesday, January 03, 2018 06:10:10 Soulsbane via Digitalmars-d-learn > wrote: > > I've only understood that imports should go in package.d. I'm seeing > > more and more packages on code.dlang.org using it for the packages > > primary code. Is this alright? As far as I can tell it's just bad > > form. It would be nice to have one of the maintainers higher up the > > food chain comment on this! [...] > In terms of functionality, there really isn't much special about > package.d. If there were, we probably wouldn't have been able to talk > Walter into it. We were able to precisely because public imports > already worked in a way that allowed package.d to work. We just needed > the feature to be added to make it possible to import a package. So, > package.d allows that, but beyond that, it's just a normal module. It > typically containts public imports for the rest of the package, but it > doesn't have to, and it can contain whatever code you want to put in > there. You can do whatever you want with it, though really, using it > for much of anything at all beyond splitting up a package in place is > beyond the scope of why it was introduced. But ultimately, there's > nothing really special about package.d, and different folks have > different ideas about it and how it should be used. [...] I personally have used package.d to put declarations that are common to a particular package, e.g., package-global enums, constants, that sort of thing. This is particular the case when the package's submodules aren't usually directly imported by outside code, in which case I tend to think of package.d as the "baseline, common declarations", and if outside code demands, it can import a more specific submodule that exposes a more specific API for that package. As Jonathan said, you can use package.d pretty much for whatever you want. T -- Claiming that your operating system is the best in the world because more people use it is like saying McDonalds makes the best food in the world. -- Carl B. Constantine
Re: How do you do "const nazi" in D?
On Wednesday, January 03, 2018 17:27:38 Marc via Digitalmars-d-learn wrote: > for a safe programming, since C/C++ times I try to make thing > const as possible. locals, parameters etc anything which isn't > going to change. > How do you do that in D? immutable everywhere? > > for example: > > foreach(Field field; fields) { > > > > immutable string htmlOutputfile = genHTMLFilename(); > > do you use immutable here? > > and on: > > Field fromFile(in string filename) { > > do you use in here if filename isn't going to change? > > I'm trying to make my own const nazi guide for D, if anyone would > like to give your opinion on this, I would be glad. Well, D's const is far more restrictive than C++'s const (and immutable even more so). So, I think that you'll find that if you slap const and immutable everywhere, you're going to have a fair bit of difficulty. Feel free to use them as much as you can get away with, but a lot of us have basically given up on using const much, because it just doesn't work in far too many cases (e.g. ranges and const don't work together at all; ranges need to be mutated to iterate). const and immutable are transitive and don't have backdoors (casting away const to mutate is undefined behavior in D, unlike C++). This means that they they provide real guarantees but also that a lot of places where folks would happily use const in C++ simply can't use const in D, either because the transitivity makes something const that wouldn't have been const in C++, or because in C++, you'd use a backdoor like mutable, and that doesn't work in D. To use const or immutable in D, the objects have to not need to mutate in any way shape or form. "Logical" const simply isn't a thing in D. In general, I'd advise using immutable over const, since it provides better optimization opportunities and allows passing objects across threads if need be, but that can often mean having to design your types differently so that they can properly function as immutable. So, good luck, but I don't know very many people who try and use const everywehre in D like you might in C++, because it's often too much of a pain to make it work if it's even possible, and if you're using ranges and templates all over the place like many of us do, it's even worse. - Jonathan M Davis
How do you do "const nazi" in D?
for a safe programming, since C/C++ times I try to make thing const as possible. locals, parameters etc anything which isn't going to change. How do you do that in D? immutable everywhere? for example: foreach(Field field; fields) { immutable string htmlOutputfile = genHTMLFilename(); do you use immutable here? and on: Field fromFile(in string filename) { do you use in here if filename isn't going to change? I'm trying to make my own const nazi guide for D, if anyone would like to give your opinion on this, I would be glad.
Re: How to use the -I command line switch?
dmd main.d C:\libs\my_module.d That does not use the -I switch. It compiles if I specify the full path to my_module.d: dmd -IC:\libs main.d C:\libs\my_module.d I don't understand the error message though.
Re: Using iopipe to stream a gzipped file
On Wednesday, 3 January 2018 at 16:09:19 UTC, Steven Schveighoffer wrote: On 1/3/18 9:45 AM, Andrew wrote: Hi, I have a very large gziped text file (all ASCII characters and ~500GB) that I want to stream and process line-by-line, and I thought the iopipe library would be perfect for this, but I can't seem to get it to work. So far, this is the closest I have to getting it to work: import iopipe.textpipe; import iopipe.zip; import iopipe.bufpipe; import iopipe.stream; void main() { auto fileToRead = openDev("file.gz").bufd.unzip(CompressionFormat.gzip); foreach (line; fileToRead.assumeText.byLineRange!false) { \\ do stuff } } but this only processes the first ~200 odd lines (I guess the initial read into the buffer). Can anyone help me out? Do you have a sample file I can play with? Your iopipe chain looks correct, so I'm not sure why it wouldn't work. -Steve A sample file (about 250MB) can be found here: ftp://ftp.1000genomes.ebi.ac.uk/vol1/ftp/release/20130502/ALL.chr22.phase3_shapeit2_mvncall_integrated_v5a.20130502.genotypes.vcf.gz It should have 1,103,800 lines, but the following code only reports 256: import iopipe.textpipe; import iopipe.zip; import iopipe.bufpipe; import iopipe.stream; import std.stdio; void main() { auto fileToRead = openDev("ALL.chr22.phase3_shapeit2_mvncall_integrated_v5a.20130502.genotypes.vcf.gz").bufd.unzip(CompressionFormat.gzip); auto counter = 0; foreach (line; fileToRead.assumeText.byLineRange!false) { counter++; } writeln(counter); } Thanks for looking into this. Andrew
Re: How do I use ncurses library with D? are there any wrapper?
On Wednesday, January 03, 2018 15:47:58 Marc via Digitalmars-d-learn wrote: > Long time ago, IIRC, I read somewhere there was a ncurses for D > but now I can't find it are there any wrapper or am I mistaken? > anyway, I'm doing it from scratch and not porting anything so > even a library with same functionality as ncurses for D is > welcome. There appear to be two which might be of use (maybe three, but the one called sf sounds more like it's using it than providing a wrapper or bindings): http://code.dlang.org/search?q=ncurses IIRC, I have a project which uses the one called ncurses so that it could take a password at the command-line without showing it. - Jonathan M Davis
Re: Efficient way to pass struct as parameter
On Wed, Jan 03, 2018 at 07:02:28AM +, Tim Hsu via Digitalmars-d-learn wrote: > On Tuesday, 2 January 2018 at 22:49:20 UTC, Adam D. Ruppe wrote: > > On Tuesday, 2 January 2018 at 22:17:14 UTC, Johan Engelen wrote: > > > Pass the Vector3f by value. > > > > This is very frequently the correct answer to these questions! Never > > assume ref is faster if speed matters - it may not be. > > However speed really matters for me. That's why you need to use a profiler to find out where the hotspots are. It may not be where you think it is. > I am writing a path tracing program. Ray will be constructed million > of times during computation. And will be passed to functions to test > intersection billion of times. After Reading comments here, it seems > ray will be passed by value to the intersection testing function. I am > not sure if ray is small enough to be passed by value. It needs some > experiment. With modern CPUs with advanced caching, it may not always be obvious whether passing by value or passing by reference is better. Always use a profiler to be sure. T -- If blunt statements had a point, they wouldn't be blunt...
Re: Using iopipe to stream a gzipped file
On 1/3/18 9:45 AM, Andrew wrote: Hi, I have a very large gziped text file (all ASCII characters and ~500GB) that I want to stream and process line-by-line, and I thought the iopipe library would be perfect for this, but I can't seem to get it to work. So far, this is the closest I have to getting it to work: import iopipe.textpipe; import iopipe.zip; import iopipe.bufpipe; import iopipe.stream; void main() { auto fileToRead = openDev("file.gz").bufd.unzip(CompressionFormat.gzip); foreach (line; fileToRead.assumeText.byLineRange!false) { \\ do stuff } } but this only processes the first ~200 odd lines (I guess the initial read into the buffer). Can anyone help me out? Do you have a sample file I can play with? Your iopipe chain looks correct, so I'm not sure why it wouldn't work. -Steve
Re: how to localize console and GUI apps in Windows
On Wednesday, 3 January 2018 at 09:11:32 UTC, thedeemon wrote: Windows API contains two sets of functions: those whose names end with A (meaning ANSI), the other where names end with W (wide characters, meaning Unicode). The sample uses TextOutA, this function that expects 8-bit encoding. Gosh, I should new this :)) Thanks for the point! TextOutW() works fine with wstring texts in this example and no more changes needed. That's just enough for this example. Thank you! Yet my particular interest is console interconnections. With the help of this forum I've learned console settings to write Cyrillic properly and simply to the console using UTF8 encoding. One thing that remains is to read and process the user's input. For now in the example I've cited above response=readln(); statement returns an empty string, in a console set for UTF8 code page, if the user's input contains any Cyrillic letters. Then the program's behavior differs depending on the compiler (or more likely on the runtime library): the one compiled with ldc continues to read on and returns empty lines, instead of the user's input, and the one compiled with dmd only returns empty lines not waiting for the user's input and not actually reading anything (i.e. it falls into indefinite loop busily printing empty response hundreds times a second). That's only for localized input. With ASCII input same program works fine. May be there is some more settings I must learn to set console to properly read non-ASCII input?
How do I use ncurses library with D? are there any wrapper?
Long time ago, IIRC, I read somewhere there was a ncurses for D but now I can't find it are there any wrapper or am I mistaken? anyway, I'm doing it from scratch and not porting anything so even a library with same functionality as ncurses for D is welcome.
Re: How to use the -I command line switch?
On Wednesday, 3 January 2018 at 12:21:28 UTC, tipdbmp wrote: // C:\libs\my_module.d module my_module; void foo() {} // main.d module main; import my_module; void main() { foo(); } Running dmd with: dmd -IC:\libs main.d my_module.d I get: Error: module my_module is in file 'my_module.d' which cannot be read import path[0] = C:\libs import path[1] = path\to\dmd\D\dmd2\windows\bin\..\..\src\phobos import path[2] = path\to\dmd\D\dmd2\windows\bin\..\..\src\druntime\import dmd main.d C:\libs\my_module.d I usually use dub for this type of thing...
Using iopipe to stream a gzipped file
Hi, I have a very large gziped text file (all ASCII characters and ~500GB) that I want to stream and process line-by-line, and I thought the iopipe library would be perfect for this, but I can't seem to get it to work. So far, this is the closest I have to getting it to work: import iopipe.textpipe; import iopipe.zip; import iopipe.bufpipe; import iopipe.stream; void main() { auto fileToRead = openDev("file.gz").bufd.unzip(CompressionFormat.gzip); foreach (line; fileToRead.assumeText.byLineRange!false) { \\ do stuff } } but this only processes the first ~200 odd lines (I guess the initial read into the buffer). Can anyone help me out? Thanks very much Andrew
Re: Help optimizing UnCompress for gzipped files
On 1/3/18 2:47 AM, Christian Köstlin wrote: On 02.01.18 21:13, Steven Schveighoffer wrote: Well, you don't need to use appender for that (and doing so is copying a lot of the data an extra time). All you need is to extend the pipe until there isn't any more new data, and it will all be in the buffer. // almost the same line from your current version auto mypipe = openDev("../out/nist/2011.json.gz") .bufd.unzip(CompressionFormat.gzip); // This line here will work with the current release (0.0.2): while(mypipe.extend(0) != 0) {} Thanks for this input, I updated the program to make use of this method and compare it to the appender thing as well. Hm.. the numbers are worse! I would have expected to be at least comparable. I'll have to look into it. Thanks for posting this. -Steve
How to use the -I command line switch?
// C:\libs\my_module.d module my_module; void foo() {} // main.d module main; import my_module; void main() { foo(); } Running dmd with: dmd -IC:\libs main.d my_module.d I get: Error: module my_module is in file 'my_module.d' which cannot be read import path[0] = C:\libs import path[1] = path\to\dmd\D\dmd2\windows\bin\..\..\src\phobos import path[2] = path\to\dmd\D\dmd2\windows\bin\..\..\src\druntime\import
Re: how to localize console and GUI apps in Windows
On Friday, 29 December 2017 at 11:14:39 UTC, zabruk70 wrote: AFAIK, Windows GUI have no ANSI/OEM problem. You can use Unicode. Be advised there are some problems with console UTF-8 input/output in Windows. The most usable is Win10 new console window but I recommend to use Windows API (WriteConsole) instead. It works correctly regardless of codepage setting, os version and C library.
Re: how to localize console and GUI apps in Windows
On Wednesday, 3 January 2018 at 09:11:32 UTC, thedeemon wrote: you need to use TextOutW that accepts 16-bit Unicode, so just convert your UTF-8 D strings to 16-bit Unicode wstrings, there are appropriate conversion functions in Phobos. Some details: import std.utf : toUTF16z; ... string s = "привет"; TextOutW(s.toUTF16z);
Buy Real passport, drivers license, IELTS, ID Cards (http://buyrealfakedocument.com)
Get Registered IELTS certificates without attending the Exam ( http://buyrealfakedocument.com ) We are a unique manufacturer of high-quality registered citizenship documents with the best machines and holograms that duplicate as database database driver's license, passports, biometric passports, residence permit, social security number SSN, birth and marriage certificates, stamps, school diplomas, IELTS and TOEFL, ESOL, Visa, Business , Students and tourists and other products for a number of countries such as USA, Canada, Germany, Sweden, Norway, Denmark, Austria, Spain, Czech Republic, Portugal, Lithuania, Russia, Hungary, Portugal, Spain, Australia, Cambodia, Croatia, African Countries, Japan, China and so on. We also provide a service to help you cross your goals, we help you to get real government issued ID, check and secure the accounts for your new ID, credit card, coach services We also deal and specialize in the production of registered TOEFL, IELTS, ESOL, CELTA/DELTA & other English Language Certificates. Please note that Our IELTS & TOEFL Certificates are Original and registered in the data base and Can be verified.After your order is placed it takes just few days for us to get your details in the system Once your details are imputed in the system it will be in the IELTS or TOEFL web sites/system once for ever and will appear real, legit and verifiable for ever. * Contact: == http://buyrealfakedocument.com/ *General Email=== http://buyrealfakedocument.com/ https://ieltscertificatoonline.com/
Re: how to localize console and GUI apps in Windows
On Wednesday, 3 January 2018 at 06:42:42 UTC, Andrei wrote: AFAIK, Windows GUI have no ANSI/OEM problem. You can use Unicode. Partly, yes. Just for a test I tried to "russify" the example Windows GUI program that comes with D installation pack (samples\d\winsamp.d). Window captions, button captions, message box texts written in UTF8 all shows fine. But direct text output functions CreateFont()/TextOut() render all Cyrillic from UTF8 strings into garbage. Windows API contains two sets of functions: those whose names end with A (meaning ANSI), the other where names end with W (wide characters, meaning Unicode). The sample uses TextOutA, this function that expects 8-bit encoding. Properly, you need to use TextOutW that accepts 16-bit Unicode, so just convert your UTF-8 D strings to 16-bit Unicode wstrings, there are appropriate conversion functions in Phobos.
Re: why @property cannot be pass as ref ?
On Saturday, 30 December 2017 at 03:49:37 UTC, ChangLong wrote: What I am try to do is implement a unique data type. (the ownership auto moved into new handle) Have you considered std.typecons.Unique[0]? If yes, in what ways does it not cover your needs? Your example code written with Unique would be something like the below, with some additions to show off more of what it can do: import std.typecons : Unique; import std.algorithm.mutation : move; void test1(size_t i) {} void test2(ref size_t i) {} void test3(ref Unique!size_t i) {} void test4(Unique!size_t i) {} unittest { static __gshared size_t socket; auto l1 = Unique!(size_t)(&socket); assert(l1 == &socket); Unique!(size_t) l2 = void; assert(!is(typeof({ l2 = l1; // Fails to compile - cannot copy Unique. }))); move(l1, l2); // Explicit move using std.algorithm.mutation.move. assert(l1 == null); // l1 has been cleared - only one reference to the data exists. assert(l2 == &socket); // l2 has the only reference. auto l3 = l2.release; // Implicit move, not unlike your byRef call. assert(l2 == null); // l2 has been cleared - only one reference to the data exists. assert(l3 == &socket); // l3 has the only reference. assert(!is(typeof({ auto l4 = l3; // Fails to compile - cannot copy Unique. }))); test1(*l3); // Can dereference and pass the pointed-to value. test2(*l3); // Can pass reference to pointed-to value[1]. test3(l3); // Lets you pass references to Unique. assert(!is(typeof({ test4(l3); // Fails to compile - cannot copy Unique. }))); } [0]: https://dlang.org/library/std/typecons/unique.html [1]: This surprised me a little - that's a new reference to the pointed-to value, which the callee could squirrel away somewhere it shouldn't. I guess it's there for ease of use. -- Simen
Re: Is it bad form to put code in package.d other than imports?
On Wednesday, 3 January 2018 at 07:43:52 UTC, Jonathan M Davis wrote: On Wednesday, January 03, 2018 06:10:10 Soulsbane via Digitalmars-d-learn wrote: [...] The entire reason that the package.d feature was added was so that it would be possible to split a module into a package without breaking code. Anything beyond that was beyond the scope of the purpose of the feature, albeit not necessarily in conflict with its original purpose. [...] Wow! Thanks Johnathan for the thorough explanation!
Re: Help optimizing UnCompress for gzipped files
On 02.01.18 14:51, Adam D. Ruppe wrote: > On Tuesday, 2 January 2018 at 10:27:11 UTC, Christian Köstlin wrote: >> After this I analyzed the first step of the process (gunzipping the >> data from a file to memory), and found out, that dlangs UnCompress is >> much slower than java, and ruby and plain c. > > Yeah, std.zlib is VERY poorly written. You can get much better > performance by just calling the C functions yourself instead. (You can > just import import etc.c.zlib; it is included still) > > Improving it would mean changing the public API. I think the one-shot > compress/uncompress functions are ok, but the streaming class does a lot > of unnecessary work inside like copying stuff around. I added a version that uses the gzip lowlevel apis (similar to my example c program). I am still having problems copying the data fast enough to an dlang array. please see the updated page: https://github.com/gizmomogwai/benchmarks/tree/master/gunzip -- Christian Köstlin