Re: Linking against clang produced libs on OSX
Hi Thank you for your help. I wrapped some functions of Qt. After updating to Qt5.0.1 it suddenly worked. The lib is c++. Its probably a bit simple. but good to know that there is no problem with clang and dmd interop so far. thx
Re: get random char from array
SaltySugar: My code: In Phobos there isn't something like random.choice() of Python. This code doesn't work with truly Unicode strings (better to use a dstring or dchar[] for that, unless you want to walk the string every time you want to extract a random item): import std.stdio, std.random; void main() { immutable array = "abcdef"; immutable rndChar = array[uniform(0, $)]; writeln(rndChar); } Bye, bearophile
Re: get random char from array
On Saturday, 2 February 2013 at 09:59:07 UTC, bearophile wrote: SaltySugar: My code: In Phobos there isn't something like random.choice() of Python. This code doesn't work with truly Unicode strings (better to use a dstring or dchar[] for that, unless you want to walk the string every time you want to extract a random item): import std.stdio, std.random; void main() { immutable array = "abcdef"; immutable rndChar = array[uniform(0, $)]; writeln(rndChar); } Bye, bearophile Thank you!
is there a way to define a pure base class that forces pureness of derived classes?
i've got something like an streaming/converter system and parts of the specialised converters are stateless other statefull is there any way to force pureness/stateless-ness through the base class or an interface in D?
Re: Why are commands executing out of order?
On 2013-02-02 07:49, Josh wrote: But main's first writeln actually outputs after f.close(). Maybe because of output buffering and you need to add flush? The program uses ~1GB of RAM overall, even though main.results is ~50MB according to memSize. Wrong comparison. You should have compared to the output file's size. info.sizeof doesn't include the size of info.name. In my test results were 30 MB but the output file was 101 MB. Any attempts to call the GC do nothing, but I'm probably doing it wrong though. Is it possible that I have a memory leak somewhere that is causing this delay, or is this a DMD problem, or something else I haven't even thought of? It's a problem with array concatenation and memory fragmentation. There are two ways out of this mess. First, there's the "Unix Way" - don't use the results array at all and print out info records immediately as they appear. Your program will use under 3 MB of RAM. :) But if you really have to do some extra processing of results, then you can reduce the memory used like 6 times by using an Appender instead of concatenating arrays and by reserving a reasonable number of records, to limit possible initial fragmentation when the array is resized. My program used 145 MB whereas the output file was 101 MB. I think it's good enough. But that's scanning just one, non-system drive. Won't even try to scan them all. Try it out: import std.datetime; import std.file; import std.stdio; import std.array; struct info { string name; bool isDir; ulong size; SysTime timeCreated; SysTime timeLastAccessed; SysTime timeLastModified; this(DirEntry d) { this.name = d.name; this.isDir = d.isDir; this.size = d.size; this.timeCreated = d.timeCreated; this.timeLastAccessed = d.timeLastAccessed; this.timeLastModified = d.timeLastModified; } } alias Appender!(info[]) InfoAppender; void main() { writeln("Scanning drives..."); info[] results; InfoAppender app = appender(results); app.reserve(512*1024); // for (char c = 'D'; c <= 'D'; c++) { if (exists(c ~ ":\\")) { app.put(info(DirEntry(c ~ ":\\"))); scan(c ~ ":\\", app); } } File f = File("driveInfo.txt", "w"); foreach (i; app.data) { f.writeln(i); } f.close(); writeln(memSize(app.data)); } void scan(string dir, ref InfoAppender app) { try { auto de = dirEntries(dir, SpanMode.shallow); foreach (d; de) { app.put(info(d)); if (d.isDir()) scan(d.name, app); } } catch (FileException fe){} } size_t memSize(T)(T[] t) { return t.length * T.sizeof; } And the preferred version to scan whole filesystem without wasting RAM: :) import std.datetime; import std.file; import std.stdio; struct info { string name; bool isDir; ulong size; SysTime timeCreated; SysTime timeLastAccessed; SysTime timeLastModified; this(DirEntry d) { this.name = d.name; this.isDir = d.isDir; this.size = d.size; this.timeCreated = d.timeCreated; this.timeLastAccessed = d.timeLastAccessed; this.timeLastModified = d.timeLastModified; } } File f; void main() { writeln("Scanning drives..."); f = File("driveInfo.txt", "w"); for (char c = 'D'; c <= 'D'; c++) { if (exists(c ~ ":\\")) { f.writeln(info(DirEntry(c ~ ":\\"))); scan(c ~ ":\\"); } } f.close(); } void scan(string dir) { try { auto de = dirEntries(dir, SpanMode.shallow); foreach (d; de) { f.writeln(info(d)); if (d.isDir()) scan(d.name); } } catch (FileException fe){} }
Re: Why are commands executing out of order?
I'm was quite surprised as I had heard the first time of these 'appender'. Therefore I'm asking me: Why is the 'appender' method so much more efficient?
std.process.system and friends
Good day, I'm trying to write a script in D for building D projects. I want to set the environment variable LIB for optlink to be able to pick up library files from where I put them after compiling dependencies. The problem is, that the std.process.setenv is only available under Linux and std.process.system("set LIB=target") does not do anything. I guess std.process.system creates a separate process every time, sets the local environment variable and exists, erasing the local environment variable. I tried supplying multiple commands at once by specifying a multi-line argument to std.process.system, but it didn't work at all. How can I set my local envoronment variables so that further calls to std.process.system can pick it up? Regards, Gor Gyolchanyan.
sc.ini
Good day, I remember hearing something about separating 32-bit and 64-bit environment configuration in sc.ini, but I don't seem to see any changes. I really don't get why is sc.ini so messed up and not working? Is it so very hard to make a configuration file? I can't get 64-bit version to work. My MSVC linker doesn't get called. Regards, Gor Gyolchanyan.
Re: Why are commands executing out of order?
On Saturday, 2 February 2013 at 11:33:07 UTC, Namespace wrote: I'm was quite surprised as I had heard the first time of these 'appender'. Therefore I'm asking me: Why is the 'appender' method so much more efficient? Because concatenation likely will end up relocating the memory over and over again (possibly lots of abandoned slices too) whereas the appender will allocated & reuse the same buffer. On the other hand you might be better off (depending on the need) with just reserving a lot more memory (close to what you need or slightly larger) and then concatenation will perform much better. But if it need to reallocate then you've still got the same problem with slices where with the appender you probably won't. I tend to reserve string concatenation for assert messages, and quicker & dirty text manipulation/building like during ctfe. Outside of those I use alternatives first.
Re: Get TypeNames of Variadic Templates
On Fri, Feb 1, 2013 at 11:04 PM, Christian Köstlin wrote: > Hi Philippe, > > wonderful solution. I also added > T get(T)() { > return components[staticIndexOf!(T, Children)]; > } > to the class to get the Children out by type (works as long as there is only > one child of each type in the tuple). Indeed, that's easier for the user this way. In that case, you might want to either return a tuple of one or more type (when there is more than one of a given type) or put a restriction on Components so it's only a set of types. Maybe with: ... if(NoDuplicates!(Children).length == Children.length) See http://dlang.org/phobos/std_typetuple.html#.NoDuplicates Then, when you're feeling masochistic, the next step is to allow assignments from other Components with a permutation of children, because Component!(int,double) is not much different from Components!(double, int) :)
Re: sc.ini
Hi, diff versions of Visual Studio may have diff installation path. So here mine in proper order: VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\ LINKCMD64=%VCINSTALLDIR%\bin\x86_amd64\link.exe WindowsSdkDir=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\ P.S.: I use: Win 8 Pro 64 bit, AMD Cpu, Visual Studio 2012 Express for Desktop.
Re: std.process.system and friends
On 02.02.2013 12:41, Gor Gyolchanyan wrote: Good day, I'm trying to write a script in D for building D projects. I want to set the environment variable LIB for optlink to be able to pick up library files from where I put them after compiling dependencies. The problem is, that the std.process.setenv is only available under Linux and std.process.system("set LIB=target") does not do anything. I guess std.process.system creates a separate process every time, sets the local environment variable and exists, erasing the local environment variable. I tried supplying multiple commands at once by specifying a multi-line argument to std.process.system, but it didn't work at all. How can I set my local envoronment variables so that further calls to std.process.system can pick it up? Have you tried putenv? It is only declared in core.sys.posix.stdlib, but the dmc-runtime-library must have it as dmd is also using it.
Associative Array, key and value as type of string or char[]
Hi all, in the moment I'm running against a wall: I want to put some strings together into an ass. array: For example a command with it's description like the following. char[char[]] ch_Description = [ 'kill' : 'kills a process', 'pause' : 'pauses a process' ] I tried with all combinations of char[char[]] over string[char[]], char[string] to string[string] with depending quotations 'abc' to "abc". My idea is just to print out the combinations to console. I'm not even .sure, if it's a good idea to do so, but what makes me cry is, after all trying, is that I can't find a solution. The compiler messages go from "no implicit conversion" to "cast(char) of string is deprecated" and others. I read much about that key-values have to be immutable and so on and I can accept the reasons, but I can't believe, there's no possible solution for my underlaying idea. Any ideas? timewulf
Re: sc.ini
On 02.02.2013 14:16, Michael wrote: Hi, diff versions of Visual Studio may have diff installation path. So here mine in proper order: VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\ LINKCMD64=%VCINSTALLDIR%\bin\x86_amd64\link.exe WindowsSdkDir=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\ P.S.: I use: Win 8 Pro 64 bit, AMD Cpu, Visual Studio 2012 Express for Desktop. You can also set 64-bit specific settings in an [Environment64] section: [Environment64] LIB="%@P%\..\..\lib64";c:\l\vc10\lib64" DFLAGS=%DFLAGS% -L/nologo I hope the dmd internal magic regarding the VCINSTALLDIR and WindowsSdkDir settings gets moved to this sections.
Re: Associative Array, key and value as type of string or char[]
It seems you are right. I get the same error. You should open a bug report for this. But as long as it isn't fixed you can use an output via foreach. import std.stdio; void main() { string[string] ch_Description = [ "kill" : "kills a process", "pause" : "pauses a process" ]; // writeln(ch_Description); // does not work, but it should foreach (string key, string value; ch_Description) { writeln(key, ':', value); } }
Re: Why are commands executing out of order?
On Saturday, 2 February 2013 at 11:16:50 UTC, FG wrote: On 2013-02-02 07:49, Josh wrote: But main's first writeln actually outputs after f.close(). Maybe because of output buffering and you need to add flush? How do I do that? I've never heard of flush before. The program uses ~1GB of RAM overall, even though main.results is ~50MB according to memSize. Wrong comparison. You should have compared to the output file's size. info.sizeof doesn't include the size of info.name. In my test results were 30 MB but the output file was 101 MB. Yeah, my output file was 126MB. I figured strings had a set amount of memory they could use, like an int can use exactly 4 bytes. But if you really have to do some extra processing of results, then you can reduce the memory used like 6 times by using an Appender instead of concatenating arrays and by reserving a reasonable number of records, to limit possible initial fragmentation when the array is resized. My program used 145 MB whereas the output file was 101 MB. I think it's good enough. I've never come across Appenders before. Could you please explain them a little bit, and what each call in your modified code does? Thanks, Josh
Re: Why are commands executing out of order?
I've never come across Appenders before. Could you please explain them a little bit, and what each call in your modified code does? Thanks, Josh http://dlang.org/phobos/std_array.html#.Appender And read Era's post.
Array concatenation vs. Appender
On 2013-02-02 13:50, Era Scarecrow wrote: On Saturday, 2 February 2013 at 11:33:07 UTC, Namespace wrote: I'm was quite surprised as I had heard the first time of these 'appender'. Therefore I'm asking me: Why is the 'appender' method so much more efficient? Because concatenation likely will end up relocating the memory over and over again (possibly lots of abandoned slices too) whereas the appender will allocated & reuse the same buffer. On the other hand you might be better off (depending on the need) with just reserving a lot more memory (close to what you need or slightly larger) and then concatenation will perform much better. But if it need to reallocate then you've still got the same problem with slices where with the appender you probably won't. Yeah but let us move reallocation out of the equation. Reserving space limits the amount of RAM used and can avoid reallocations all together but in a little test it came out that still appender is 2.5-4 times faster than tab ~= str, where tab is char[] (same when it is ubyte[]). Why is that? Let's say we have this code: char[] tab; string fill = "1234"; uint loops = 100_000_000; tab.reserve(loops * fill.length); foreach (i; 0..loops) tab ~= fill; Using Appender changes the above loop into something like this: size_t capacity = tab.capacity; foreach (i; 0..loops) { size_t flen = fill.length; size_t len = tab.length; if (len + flen > capacity) { ... // use GC.extend or GC.qalloc & memcpy // update capacity and assign tab = memory_block[0..len] } tab = tab.ptr[0..len+flen]; tab.ptr[len..len+flen] = fill[]; } Why cannot tab ~= fill achieve similar performance as this code? Am I missing something important?
Re: Why are commands executing out of order?
On 2013-02-02 16:22, Josh wrote: Maybe because of output buffering and you need to add flush? How do I do that? I've never heard of flush before. writeln("..."); stdout.flush(); C also has flush, in the form of fflush(stdout); I've never come across Appenders before. Could you please explain them a little bit, and what each call in your modified code does? I'm baffled myself as to why they perform better than normal array concatenation. We'll see if some interesting explanation appears. That's why I changed the topic to "Array concatenation vs. Appender".
Re: Associative Array, key and value as type of string or char[]
On 02.02.2013 16:06, Namespace wrote: > import std.stdio; > > void main() { > string[string] ch_Description = [ > "kill" : "kills a process", > "pause" : "pauses a process" > ]; > > // writeln(ch_Description); // does not work, but it should > foreach (string key, string value; ch_Description) { > writeln(key, ':', value); > } > } Thanks for the answer. I tried your code and very surprisingly: It works on both ways. After searching for the differences to my code, I found my fault: import std.stdio; string[string] ch_Description = [ "kill" : "kills a process", "pause" : "pauses a process" ]; void main() { writeln(ch_Description); // does not work, but it should foreach (string key, string value; ch_Description) { writeln(key, ':', value); } } I declared the array outside of main(), because I wanted to use them in more than one function. The errors I got were all, because of this first one, "src/tstsuite.d(3): Error: non-constant expression ["kill":"kills a process","pause":"pauses a process"]" which shows up when compiling this simple example. After checking this, I stripped down my program from unneeded casts and so on and now I see the same error message as above. It just didn't come up, because of my workarounds, which created the other failures. Thanks for showing me the forest behind this big tree ;-) Now I've just to look, how to declare this array in the way of public constants. Thanks and have nice weekend!
Re: Associative Array, key and value as type of string or char[]
On 2013-02-02 16:06, Namespace wrote: string[string] ch_Description = [ "kill" : "kills a process", "pause" : "pauses a process" ]; writeln(ch_Description); // does not work, but it should Doesn't work in the current version? In DMD 2.060 it works.
Re: Associative Array, key and value as type of string or char[]
On Saturday, 2 February 2013 at 16:06:09 UTC, FG wrote: On 2013-02-02 16:06, Namespace wrote: string[string] ch_Description = [ "kill" : "kills a process", "pause" : "pauses a process" ]; writeln(ch_Description); // does not work, but it should Doesn't work in the current version? In DMD 2.060 it works. I've cloned the github version two days ago and with that I get lots of errors. Maybe I should open a bug report. :)
Re: Get TypeNames of Variadic Templates
Yes! very good idea! I also added something like static assert(staticIndexOf!(T, Children) != -1); to get a compile time error when someone wants to get something which is not there. thanks christian On 2/2/13 14:13 , Philippe Sigaud wrote: On Fri, Feb 1, 2013 at 11:04 PM, Christian Köstlin wrote: Hi Philippe, wonderful solution. I also added T get(T)() { return components[staticIndexOf!(T, Children)]; } to the class to get the Children out by type (works as long as there is only one child of each type in the tuple). Indeed, that's easier for the user this way. In that case, you might want to either return a tuple of one or more type (when there is more than one of a given type) or put a restriction on Components so it's only a set of types. Maybe with: ... if(NoDuplicates!(Children).length == Children.length) See http://dlang.org/phobos/std_typetuple.html#.NoDuplicates Then, when you're feeling masochistic, the next step is to allow assignments from other Components with a permutation of children, because Component!(int,double) is not much different from Components!(double, int) :)
Re: Associative Array, key and value as type of string or char[]
On 02.02.2013 17:06, FG wrote: > On 2013-02-02 16:06, Namespace wrote: >> string[string] ch_Description = [ >> "kill" : "kills a process", >> "pause" : "pauses a process" >> ]; >> >> writeln(ch_Description); // does not work, but it should > > Doesn't work in the current version? In DMD 2.060 it works. I tried in dmd 2.061 and git-version from yesterday: Both work!
Re: Associative Array, key and value as type of string or char[]
Works now.
new T[size] vs .reserve
Currently something like new ubyte[4]; reserves space for _at least_ 4 items. But if I want to store now something, the index isn't 0, it's 4. Let me explain that on a brief example: [code] import std.stdio; void main() { ubyte[] arr = new ubyte[4]; arr ~= 4; // desirable: [4, 0, 0, 0]; writeln(arr); // prints: [0, 0, 0, 0, 4] ubyte[] arr2; arr2.reserve(4); arr2 ~= 4; // expect: [4, 0, 0, 0]; writeln(arr2); // prints: [4] just as well } [/code] So is there any reason why this behaviour is like it is? As I looked at arr.length and arr.capacity for the first time I was schocked: I want only space for 4 items, but I got space for 15. I read in the docs that .reserve extends the space to at least SIZE items, but maybe more. But at that time and still yet I found nothing about new ubyte[SIZE]. So I ask: wouldn't it be better, if new ubyte[4] reserves only space for 4 items and reallocs only if I append more than 4?
Re: new T[size] vs .reserve
On Saturday, 2 February 2013 at 16:36:29 UTC, Namespace wrote: Currently something like new ubyte[4]; reserves space for _at least_ 4 items. But if I want to store now something, the index isn't 0, it's 4. Let me explain that on a brief example: [code] import std.stdio; void main() { ubyte[] arr = new ubyte[4]; You asked for array with four zeros (T.init for ubyte is 0). arr ~= 4; // desirable: [4, 0, 0, 0]; writeln(arr); // prints: [0, 0, 0, 0, 4] You got it. And you appended 4 to them, so you got proper result. ubyte[] arr2; You asked for empty array. arr2.reserve(4); arr2 ~= 4; // expect: [4, 0, 0, 0]; writeln(arr2); // prints: [4] just as well } You appended 4 to empty array and you got [4]. By the way, note that the output is not [4,0,0,0] it is [4] since no one has pushed three zeros there. [/code] So is there any reason why this behaviour is like it is? I found it is consistent and complying yo spec. new ubyte[4] and reverse(4) do different things. As I looked at arr.length and arr.capacity for the first time I was schocked: I want only space for 4 items, but I got space for 15. I read in the docs that .reserve extends the space to at least SIZE items, but maybe more. But at that time and still yet I found nothing about new ubyte[SIZE]. So I ask: wouldn't it be better, if new ubyte[4] reserves only space for 4 items and reallocs only if I append more than 4? Since you have two tools which do different things, you can select that tool which does what you wanted. What's the problem here?
Re: new T[size] vs .reserve
No one said that this is a problem, or? (; But why should I generate an array with size 4 if an append of me resize it to 5? I'm asking because we have currently nothing (nice) for _fixed_ size arrays at runtime. That should be change. Therefore new T[size] would be a good.
Re: new T[size] vs .reserve
On 2013-02-02 17:36, Namespace wrote: ubyte[] arr = new ubyte[4]; arr ~= 4; // desirable: [4, 0, 0, 0]; Why not arr[0] = 4? What is so special about having 4 elements? As I looked at arr.length and arr.capacity for the first time I was schocked: I want only space for 4 items, but I got space for 15. I think you are out of luck with built-in dynamic arrays. It seems that even for an array of length 1 it gives a minimum of 15 bytes storage, so you can fit 15 bytes, 7 shorts, 3 ints, 1 long. I'm not sure why is it 15, given alignment an all...
Re: Not able to get scaled performance on increasing number of threads
02-Feb-2013 00:39, FG пишет: On 2013-02-01 20:33, Dmitry Olshansky wrote: Mine reiteration on it, with a bit of help from std.parallelism. std.parallelism uses thread pool thus it's somewhat faster then creating threads anew. Interestingly, threads+barrier here wasn't much slower than tasks: 14% slower for dmd32, only 5% for gdc64 (and taskpool in dmd 13% slower than in gdc). I'm think that taskPool should provide better operation for 'wait till all tasks are finished' as yielding on each task (i.e. future) looks less efficient. That being said I might be missing something in std.parallelism API, I haven't used it all that much before. But I love foreach(v; parallel(range) stuff :) -- Dmitry Olshansky
Re: new T[size] vs .reserve
On Saturday, 2 February 2013 at 17:48:14 UTC, FG wrote: On 2013-02-02 17:36, Namespace wrote: ubyte[] arr = new ubyte[4]; arr ~= 4; // desirable: [4, 0, 0, 0]; Why not arr[0] = 4? What is so special about having 4 elements? Example: struct Color { public: ubyte[4] colors; } ubyte[] data = new ubyte[color_data.length * 4]; // enough storage foreach (ref const Color col; color_data) { data ~= col.colors; } Currently impossible, even with self indexing absolute annoying and unnecessary complicated. Sure you could do the same with .reserve but the point is that you does not want more storage than color_data.length * 4. Currently I use my own struct which reserve only color_data.length * 4 memory and let the index at beginning to 0. But I'm using D because it is nice and simple, so why I should create my own data structure, and use ugly malloc, realloc and free, for such needed thing if the language could and should do that for you?
Re: sc.ini
02-Feb-2013 18:55, Rainer Schuetze пишет: On 02.02.2013 14:16, Michael wrote: Hi, diff versions of Visual Studio may have diff installation path. So here mine in proper order: VCINSTALLDIR=C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\ LINKCMD64=%VCINSTALLDIR%\bin\x86_amd64\link.exe WindowsSdkDir=C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\ P.S.: I use: Win 8 Pro 64 bit, AMD Cpu, Visual Studio 2012 Express for Desktop. You can also set 64-bit specific settings in an [Environment64] section: [Environment64] LIB="%@P%\..\..\lib64";c:\l\vc10\lib64" DFLAGS=%DFLAGS% -L/nologo I hope the dmd internal magic regarding the VCINSTALLDIR and WindowsSdkDir settings gets moved to this sections. Mmm.. great, thanks. I've also been wondering how to make separate 64-bit config on Windows, as before I messed up one or the other. -- Dmitry Olshansky
Re: new T[size] vs .reserve
On 2013-02-02 19:01, Namespace wrote: Example: struct Color { public: ubyte[4] colors; } ubyte[] data = new ubyte[color_data.length * 4]; // enough storage foreach (ref const Color col; color_data) { data ~= col.colors; } Sorry, but what is the point of data having only 4 bytes reserved at the beginning? What is wrong with this: ubyte[] data; data.reserve(color_data.length * 4); foreach (ref const Color col; color_data) data ~= col.colors; Are you uncomfortable, because it may allocate twice as much space as you need (for bigger color_data)?
Re: new T[size] vs .reserve
Are you uncomfortable, because it may allocate twice as much space as you need (for bigger color_data)? Yes, that's the point. Sorry, I cannot express myself very well in English.
Re: new T[size] vs .reserve
On 2013-02-02 19:53, Namespace wrote: Are you uncomfortable, because it may allocate twice as much space as you need (for bigger color_data)? Yes, that's the point. Sorry, I cannot express myself very well in English. You're right. It's surprising for anyone used to dealing with std::vector, that it actually reserves more than you specify. Another odd thing - when pushing back to a vector its capacity grows: 1, 2, 4, 8, 16, 32 ..., but with D arrays it's like 7, 15, 31, 63... Why 2**n - 1? What secret data is hidden after the block? ;)
Re: Array concatenation vs. Appender
On Sat, 02 Feb 2013 10:47:39 -0500, FG wrote: On 2013-02-02 13:50, Era Scarecrow wrote: On Saturday, 2 February 2013 at 11:33:07 UTC, Namespace wrote: I'm was quite surprised as I had heard the first time of these 'appender'. Therefore I'm asking me: Why is the 'appender' method so much more efficient? Because concatenation likely will end up relocating the memory over and over again (possibly lots of abandoned slices too) whereas the appender will allocated & reuse the same buffer. On the other hand you might be better off (depending on the need) with just reserving a lot more memory (close to what you need or slightly larger) and then concatenation will perform much better. But if it need to reallocate then you've still got the same problem with slices where with the appender you probably won't. Yeah but let us move reallocation out of the equation. Reserving space limits the amount of RAM used and can avoid reallocations all together but in a little test it came out that still appender is 2.5-4 times faster than tab ~= str, where tab is char[] (same when it is ubyte[]). Why is that? Let's say we have this code: char[] tab; string fill = "1234"; uint loops = 100_000_000; tab.reserve(loops * fill.length); foreach (i; 0..loops) tab ~= fill; Using Appender changes the above loop into something like this: size_t capacity = tab.capacity; foreach (i; 0..loops) { size_t flen = fill.length; size_t len = tab.length; if (len + flen > capacity) { ... // use GC.extend or GC.qalloc & memcpy // update capacity and assign tab = memory_block[0..len] } tab = tab.ptr[0..len+flen]; tab.ptr[len..len+flen] = fill[]; } Why cannot tab ~= fill achieve similar performance as this code? Am I missing something important? Appender is built for appending and has higher up-front costs, and higher memory costs. Normal arrays can be used for appending, but also can be used for so many other things. In other words, Appender cannot have the features that standard arrays have in order to make appending as fast as possible. -Steve
Re: new T[size] vs .reserve
On Sat, 02 Feb 2013 11:36:28 -0500, Namespace wrote: Currently something like new ubyte[4]; reserves space for _at least_ 4 items. But if I want to store now something, the index isn't 0, it's 4. Let me explain that on a brief example: [code] import std.stdio; void main() { ubyte[] arr = new ubyte[4]; arr ~= 4; // desirable: [4, 0, 0, 0]; writeln(arr); // prints: [0, 0, 0, 0, 4] ubyte[] arr2; arr2.reserve(4); arr2 ~= 4; // expect: [4, 0, 0, 0]; writeln(arr2); // prints: [4] just as well } [/code] So is there any reason why this behaviour is like it is? As I looked at arr.length and arr.capacity for the first time I was schocked: I want only space for 4 items, but I got space for 15. I read in the docs that .reserve extends the space to at least SIZE items, but maybe more. But at that time and still yet I found nothing about new ubyte[SIZE]. So I ask: wouldn't it be better, if new ubyte[4] reserves only space for 4 items and reallocs only if I append more than 4? Heap block sizes start at 16. One byte overhead is used to store the array length, so the minimum size of ANY array allocation is 15 bytes. Then it doubles to 32, then to 64, then to 128, 256, 512, etc. until you get to a page size (4096). Then it scales linearly by pages. I think you misunderstand what reserve and append do. You should read this article to understand arrays and appending better: http://dlang.org/d-array-article.html -Steve
Re: new T[size] vs .reserve
On Saturday, 2 February 2013 at 19:49:39 UTC, FG wrote: On 2013-02-02 19:53, Namespace wrote: Are you uncomfortable, because it may allocate twice as much space as you need (for bigger color_data)? Yes, that's the point. Sorry, I cannot express myself very well in English. You're right. It's surprising for anyone used to dealing with std::vector, that it actually reserves more than you specify. FYI: std::vector will do exactly the same thing. The actual grow scheme may be different, but that is purelly an implementation detail. Another thing to take into account: In C++, if you request 10 bytes of allocation space, but the underlying implementation actually allocates a 32 byte block, you'll know nothing of it. If later, you want to grow those 10 bytes to 20 bytes, you'll have to request a new allocation. std::vector has actually no idea how much space actually gets allocated. It requests a certain amount but has no idea how much it really gets. At best, it can tell you how much it requested. In D, you can exploit the last drop of allocation space actually allocated. It is the underlying array itself that tells you how much space there is left. Another odd thing - when pushing back to a vector its capacity grows: 1, 2, 4, 8, 16, 32 ..., but with D arrays it's like 7, 15, 31, 63... Why 2**n - 1? What secret data is hidden after the block? ;) The currently used size. In C++, set::vector is a struct that has a "size" member, and a pointer to a payload. In D, the "size" data is embedded straight into the payload. Kind of like how std::string is implemented actually. This has a two-fold advantage: The actual slice object is light (just a fat pointer). Also, when you have two (or more) slices that reference the same data, they *know* if or if not they can safelly append, without cloberring the data of another slice. I suggest you read this: http://dlang.org/d-array-article.html It is a very interesting read, especially for those of us with C++ background. One very (very) important thing to realize is that std::vector is a container. D slices are not containers: they are ranges. They iterate on an underlying array object, but they are not containers themselves. The underlying object, the so called "dynamic array" is actually a obscure and hidden object you cannot access dirrectly. There is some ambiguity between both terms, and they are often used interchangedbly, but to really understand what is going on, you need to imagine them as two different objects interacting.
Re: new T[size] vs .reserve
On 2013-02-02 22:33, Steven Schveighoffer wrote: Heap block sizes start at 16. One byte overhead is used to store the array length, so the minimum size of ANY array allocation is 15 bytes. How is the length stored because I see only strange numbers in that byte. foreach (end; 2..31) { ubyte[] x; foreach (i; 0..end) { x ~= cast(ubyte)i; } writeln(x.length, " ", x.capacity, " ", x.ptr[end]); } That code outputs following length/capacity/extra_byte: 2 15 69 3 15 0 4 15 100 5 15 26 6 15 36 7 15 0 8 15 0 9 15 0 10 15 0 11 15 0 12 15 0 13 15 0 14 15 0 15 15 15 16 31 0 17 31 0 18 31 0 19 31 0 20 31 0 21 31 0 22 31 0 23 31 0 24 31 0 25 31 0 26 31 0 27 31 0 28 31 0 29 31 0 30 31 0 Last byte's value for length == 2 is quite random on each execution. In a smaller way also for length == 6. Other values seem constant.
Re: new T[size] vs .reserve
My real question was: will we ever have fixed size arrays at runtime?
Re: new T[size] vs .reserve
On 2013-02-02 22:57, FG wrote: On 2013-02-02 22:33, Steven Schveighoffer wrote: Heap block sizes start at 16. One byte overhead is used to store the array length, so the minimum size of ANY array allocation is 15 bytes. How is the length stored because I see only strange numbers in that byte. foreach (end; 2..31) { ubyte[] x; foreach (i; 0..end) { x ~= cast(ubyte)i; } writeln(x.length, " ", x.capacity, " ", x.ptr[end]); } Ah, sorry. Silly me. I have figured out that the length byte would have to be aligned to the end of the block, so that is where I should look. The updated code: // size_t ends = [1,2,7,15,31]; // crashes DMD foreach (end; 2..31) { ubyte[] x; foreach (i; 0..end) { x ~= cast(ubyte)i; } writeln(x.length, " ", x.capacity, " ", x.ptr[x.capacity]); } return; shows that indeed, there's length written at the end. :) Output: 2 15 2 3 15 3 4 15 4 5 15 5 6 15 6 7 15 7 8 15 8 9 15 9 10 15 10 11 15 11 12 15 12 13 15 13 14 15 14 15 15 15 16 31 16 17 31 17 18 31 18 19 31 19 20 31 20 21 31 21 22 31 22 23 31 23 24 31 24 25 31 25 26 31 26 27 31 27 28 31 28 29 31 29 30 31 30
Re: new T[size] vs .reserve
On Saturday, 2 February 2013 at 22:15:56 UTC, Namespace wrote: My real question was: will we ever have fixed size arrays at runtime? I see no reason why we couldn't, the only problem is a syntax one. If you beat the syntax (by wrapping it in a struct) then you can do it no problem: // T[N]* makeFixed(size_t N, T)() { static struct Fixed { T[N] a; } auto p = new Fixed(); return &((*p).a); } void main() { int[4]* p4 = makeFixed!(4, int)(); } // And there, a dynamically allocated fixed size array. I know it's not pretty, but it proves the point.
Re: new T[size] vs .reserve
On 2013-02-02 22:47, monarch_dodra wrote: I suggest you read this: http://dlang.org/d-array-article.html It is a very interesting read, especially for those of us with C++ background. Thank you for pointing me to that article. I have read it months ago and forgotten the important parts. Now it (slices & arrays) finally started making sense again. :)
Re: new T[size] vs .reserve
On Saturday, 2 February 2013 at 22:39:58 UTC, monarch_dodra wrote: On Saturday, 2 February 2013 at 22:15:56 UTC, Namespace wrote: My real question was: will we ever have fixed size arrays at runtime? I see no reason why we couldn't, the only problem is a syntax one. If you beat the syntax (by wrapping it in a struct) then you can do it no problem: // T[N]* makeFixed(size_t N, T)() { static struct Fixed { T[N] a; } auto p = new Fixed(); return &((*p).a); } void main() { int[4]* p4 = makeFixed!(4, int)(); } // And there, a dynamically allocated fixed size array. I know it's not pretty, but it proves the point. Sure and as I said: something like that I'm using currently. It is very ugly and because of that I asked for a built in solution, like new ubyte[size]. C have also runtime fixed size arrays. But as far as I can see all your are fine with the wrapped struct solution.
Re: new T[size] vs .reserve
But as far as I can see all your are fine with the wrapped struct solution. -> But as far as I can see, all of you are happy with the current wrapped struct solution. We need an 'edit' button.
Re: Array concatenation vs. Appender
On Saturday, 2 February 2013 at 15:47:37 UTC, FG wrote: Yeah but let us move reallocation out of the equation. Reserving space limits the amount of RAM used and can avoid reallocations all together but in a little test it came out that still appender is 2.5-4 times faster than tab ~= str, where tab is char[] (same when it is ubyte[]). Why is that? Reserving doesn't mean it has to allocate any memory at all; That's up to the implementation of the runtime and OS, it may just say 'any allocations not related to this object start after address xxx', then as the reserved space needs more it requests the larger space from the OS. The limitations of how much you can use memory-wise doesn't change as that's determined by the infrastructure. (VM and harddrive space doesn't count). Why cannot tab ~= fill achieve similar performance as this code? Am I missing something important? As for how many checks and overhead the runtime has I'm not sure. Try compiling the code again with full optimizations on and see if it makes a difference. Concatenation may perform better like that (as long as relocation/copying isn't done) or maybe not...
Re: Array concatenation vs. Appender
On Sunday, February 03, 2013 02:27:16 Era Scarecrow wrote: > On Saturday, 2 February 2013 at 15:47:37 UTC, FG wrote: > > Yeah but let us move reallocation out of the equation. > > Reserving space limits the amount of RAM used and can avoid > > reallocations all together but in a little test it came out > > that still appender is 2.5-4 times faster than tab ~= str, > > where tab is char[] (same when it is ubyte[]). Why is that? > > Reserving doesn't mean it has to allocate any memory at all; > That's up to the implementation of the runtime and OS, it may > just say 'any allocations not related to this object start after > address xxx', then as the reserved space needs more it requests > the larger space from the OS. The limitations of how much you can > use memory-wise doesn't change as that's determined by the > infrastructure. (VM and harddrive space doesn't count). reserve should guarantee that you have at least the requested amount of memory already allocated, or it's broken. Its whole purpose is to guarantee that capacity is at least as large as the amount being reserved so that you can do a single allocation up front rather than having to worry about reallocations occuring as you append. - Jonathan M Davis
Re: Array concatenation vs. Appender
On Sunday, 3 February 2013 at 01:41:26 UTC, Jonathan M Davis wrote: reserve should guarantee that you have at least the requested amount of memory already allocated, or it's broken. Its whole purpose is to guarantee that capacity is at least as large as the amount being reserved so that you can do a single allocation up front rather than having to worry about reallocations occurring as you append. Allocated, set aside, uninterrupted continuous block, etc. As long as the space is actually available when it's needed it's implemented doesn't matter. In the end it's up to the OS. The OS could be using Virtual Memory space by compressing data, then decompressing when it's requested/needed; In that case the data pre-allocated is empty (zeroed) it can compress instantly to almost nothing (Compressed swapfile driver in Linux for example). The most important part is making sure nothing else can claim any memory in the reserved block.
shell doesn't throw on error. Is that a regression?
The doc for std.process.shell says "If the process could not be started or exits with an error code, throws an exception." However on OSX I'm having a different kind of behavior. Isn't there a unittest to test this? --- import std.process; import std.stdio; void main(){ shell("asfasfasdfasdf"); writeln("ok"); } --- prints: in dmd.2.061 - 2.059: sh: asfasfasdfasdf: command not found ok in dmd.2.057: sh: asfasfasdfasdf: command not found std.exception.ErrnoException@std/stdio.d(418): Could not close pipe `asfasfasdfasdf' (Undefined error: 0)
Re: shell doesn't throw on error. Is that a regression?
On 2/3/13, timotheecour wrote: > Isn't there a unittest to test this? The only unittest is unfortunately pretty bad: unittest { auto x = shell("echo wyda"); } Please feel free to file a bug: http://d.puremagic.com/issues/enter_bug.cgi?product=D
why does array appending add a page size instead of doubling ?
What's the rationale behind array appending adding a page size to capacity instead of doubling, after the size of the array reaches a certain size (cf what std::vector does) ? That seems like an example of (evil?) early optimization. T[]a; int n=some big value; foreach(i;0..n) a~=T.init; Depending on T.sizeof or n, the code above will be linear complexity in n (while capacity remains below page size) or quadratic (while capacity increments are one page at a time). The C++ version doesn't have this problem, as doubling is always the case (in most implementations at least). std::vectora; int n=some big value; for(int i=0;iNote that we can't always use a.reserve(n) as in more complex examples, we don't know final size. And appender is more restrictive. Would love some explanations!
Re: shell doesn't throw on error. Is that a regression?
here goes: http://d.puremagic.com/issues/show_bug.cgi?id=9444 please see my added comment in 9444 regarding capturing std err instead of displaying it.
Re: new T[size] vs .reserve
On Sunday, 3 February 2013 at 00:34:48 UTC, Namespace wrote: C have also runtime fixed size arrays. They were added in C99 (variable length arrays, they're called). C++, on the other hand, still doesn't have them.
Re: shell doesn't throw on error. Is that a regression?
On Sunday, 3 February 2013 at 02:28:26 UTC, timotheecour wrote: here goes: http://d.puremagic.com/issues/show_bug.cgi?id=9444 please see my added comment in 9444 regarding capturing std err instead of displaying it. actually the new std.process pull request (http://forum.dlang.org/thread/k5uprq$obu$1...@digitalmars.com) works well. I wonder when that'll get in master?
Re: Associative Array, key and value as type of string or char[]
On 02/02/2013 08:00 AM, timewulf wrote: > After searching for the differences to my code, I found my fault: It is not your fault. :) > Now I've just to look, how to declare this array in the way of public > constants. You need 'static this()': import std.stdio; string[string] ch_Description; static this() { ch_Description = [ "kill" : "kills a process", "pause" : "pauses a process" ]; } void main() { // ... } You can even make the AA immutable if it never changes: immutable string[string] ch_Description; Ali
Re: why does array appending add a page size instead of doubling ?
On 02/02/2013 08:37 PM, Ali Çehreli wrote: > On 02/02/2013 06:22 PM, timotheecour wrote: > > What's the rationale behind array appending adding a page size to > > capacity > > It is not always the case. The page is added only if the next page > conveniently free. There is no cost for that "allocation". I have tested this for D and C++ with the following programs. They count the number of times the underlying buffer gets reallocated and the number of elements that get moved as a result of that. Here is the C++ program: #include #include using namespace std; int main() { for (size_t maxElements = 1; maxElements <= 0x400; maxElements *= 2) { vector s; size_t totalElementsMoved = 0; size_t totalAllocations = 0; for (size_t i = 0; i < maxElements; ++i) { int *oldPtr = s.empty() ? NULL : &s[0]; s.push_back(0); if (&s[0] != oldPtr) { totalElementsMoved += (s.size() - 1); ++totalAllocations; } } cout << "Elements: " << maxElements << " Allocations: " << totalAllocations << " Moved: " << totalElementsMoved << '\n'; } } It indeed shows amortized constant growth. The total number of elements that get moved is always one less than the eventual size of the array and the number of times of the allocations is predictable: Elements: 1 Allocations: 1 Moved: 0 Elements: 2 Allocations: 2 Moved: 1 Elements: 4 Allocations: 3 Moved: 3 Elements: 8 Allocations: 4 Moved: 7 Elements: 16 Allocations: 5 Moved: 15 Elements: 32 Allocations: 6 Moved: 31 Elements: 64 Allocations: 7 Moved: 63 Elements: 128 Allocations: 8 Moved: 127 Elements: 256 Allocations: 9 Moved: 255 Elements: 512 Allocations: 10 Moved: 511 Elements: 1024 Allocations: 11 Moved: 1023 Elements: 2048 Allocations: 12 Moved: 2047 Elements: 4096 Allocations: 13 Moved: 4095 Elements: 8192 Allocations: 14 Moved: 8191 Elements: 16384 Allocations: 15 Moved: 16383 Elements: 32768 Allocations: 16 Moved: 32767 Elements: 65536 Allocations: 17 Moved: 65535 Elements: 131072 Allocations: 18 Moved: 131071 Elements: 262144 Allocations: 19 Moved: 262143 Elements: 524288 Allocations: 20 Moved: 524287 Elements: 1048576 Allocations: 21 Moved: 1048575 Elements: 2097152 Allocations: 22 Moved: 2097151 Elements: 4194304 Allocations: 23 Moved: 4194303 Elements: 8388608 Allocations: 24 Moved: 8388607 Elements: 16777216 Allocations: 25 Moved: 16777215 Elements: 33554432 Allocations: 26 Moved: 33554431 Elements: 67108864 Allocations: 27 Moved: 67108863 Here is the D program: import std.stdio; void main() { for (auto maxElements = 1; maxElements <= 0x400_; maxElements *= 2) { int[] s; auto totalElementsMoved = 0; auto totalAllocations = 0; foreach (i; 0 .. maxElements) { auto oldPtr = s.ptr; s ~= 0; if (s.ptr != oldPtr) { totalElementsMoved += (s.length - 1); ++totalAllocations; } } writefln("Elements: %s, Allocations: %s, Moved: %s", maxElements, totalAllocations, totalElementsMoved); } } Its output is different in that the number of allocations is less than C++ but the total number of elements that get moved are more: Elements: 1, Allocations: 1, Moved: 0 Elements: 2, Allocations: 1, Moved: 0 Elements: 4, Allocations: 2, Moved: 3 Elements: 8, Allocations: 3, Moved: 10 Elements: 16, Allocations: 4, Moved: 25 Elements: 32, Allocations: 5, Moved: 56 Elements: 64, Allocations: 6, Moved: 119 Elements: 128, Allocations: 7, Moved: 246 Elements: 256, Allocations: 8, Moved: 501 Elements: 512, Allocations: 9, Moved: 1012 Elements: 1024, Allocations: 9, Moved: 1012 Elements: 2048, Allocations: 9, Moved: 1012 Elements: 4096, Allocations: 9, Moved: 1012 Elements: 8192, Allocations: 9, Moved: 1012 Elements: 16384, Allocations: 9, Moved: 1012 Elements: 32768, Allocations: 9, Moved: 1012 Elements: 65536, Allocations: 9, Moved: 1012 Elements: 131072, Allocations: 10, Moved: 28655 Elements: 262144, Allocations: 9, Moved: 1012 Elements: 524288, Allocations: 12, Moved: 435173 Elements: 1048576, Allocations: 13, Moved: 1431520 Elements: 2097152, Allocations: 11, Moved: 1993706 Elements: 4194304, Allocations: 13, Moved: 5877728 Elements: 8388608, Allocations: 14, Moved: 14838747 Elements: 16777216, Allocations: 12, Moved: 30438373 Elements: 33554432, Allocations: 12, Moved: 59881445 Elements: 67108864, Allocations: 12, Moved: 109627365 Ali
Re: is there a way to define a pure base class that forces pureness of derived classes?
On 02/02/2013 02:23 AM, dennis luehring wrote: i've got something like an streaming/converter system and parts of the specialised converters are stateless other statefull is there any way to force pureness/stateless-ness through the base class or an interface in D? That seems to be the case: interface I { int foo() const pure; } int g; class C : I { int foo() const { return g;// ERROR: pure function 'deneme.C.foo' cannot access //mutable static data 'g' } } void main() { auto o = new C; o.foo(); } Note that there is no 'pure' on C.foo; it is inherited from I.foo. Ali
Re: why does array appending add a page size instead of doubling ?
Okay, I've got a question for you Ali... why is it that sometimes as Elements increased, there were a _drop_ of allocations? So, these in particular: On Sunday, 3 February 2013 at 06:02:04 UTC, Ali Çehreli wrote: Elements: 65536, Allocations: 9, Moved: 1012 Elements: 131072, Allocations: 10, Moved: 28655 [[ Elements: 262144, Allocations: 9, Moved: 1012 ]] Elements: 524288, Allocations: 12, Moved: 435173 Elements: 1048576, Allocations: 13, Moved: 1431520 [[ Elements: 2097152, Allocations: 11, Moved: 1993706 ]] Elements: 4194304, Allocations: 13, Moved: 5877728 Elements: 8388608, Allocations: 14, Moved: 14838747 [[ Elements: 16777216, Allocations: 12, Moved: 30438373 ]] Elements: 33554432, Allocations: 12, Moved: 59881445 Elements: 67108864, Allocations: 12, Moved: 109627365 That's quite an oddity to me, especially looking at the code.
Re: Associative Array, key and value as type of string or char[]
On 03.02.2013 06:09, Ali Çehreli wrote: > You need 'static this()': > > import std.stdio; > > string[string] ch_Description; > > static this() > { > ch_Description = [ "kill" : "kills a process", >"pause" : "pauses a process" ]; > } > > void main() { > // ... > } > > You can even make the AA immutable if it never changes: > > immutable string[string] ch_Description; > > Ali > Thanks, I applied both and errors are gone. Timewulf
Re: why does array appending add a page size instead of doubling ?
On 02/02/2013 10:48 PM, Chris Cain wrote: > Okay, I've got a question for you Ali... why is it that sometimes as > Elements increased, there were a _drop_ of allocations? > > So, these in particular: > > On Sunday, 3 February 2013 at 06:02:04 UTC, Ali Çehreli wrote: >> Elements: 65536, Allocations: 9, Moved: 1012 >> Elements: 131072, Allocations: 10, Moved: 28655 >> [[ Elements: 262144, Allocations: 9, Moved: 1012 ]] >> Elements: 524288, Allocations: 12, Moved: 435173 >> Elements: 1048576, Allocations: 13, Moved: 1431520 >> [[ Elements: 2097152, Allocations: 11, Moved: 1993706 ]] >> Elements: 4194304, Allocations: 13, Moved: 5877728 >> Elements: 8388608, Allocations: 14, Moved: 14838747 >> [[ Elements: 16777216, Allocations: 12, Moved: 30438373 ]] >> Elements: 33554432, Allocations: 12, Moved: 59881445 >> Elements: 67108864, Allocations: 12, Moved: 109627365 > > That's quite an oddity to me, especially looking at the code. We must be seeing the effects of how the GC works. Note that each line is printed for a different slice 's'. My guess is that the GC runs a collection right before the observed drop and the next array gets lucky. Ali