Thread overview
Help with Associative array problems.
Apr 02, 2008
Spacen Jasset
Apr 02, 2008
Frits van Bommel
Apr 02, 2008
Spacen Jasset
Apr 03, 2008
Frits van Bommel
April 02, 2008
The program below does not print what it should, either using a File or the TArrayStream.

It prints this:

user@vm-fruitbat:~$ dmd t.d
user@vm-fruitbat:~$ ./t
Error: 4invalid UTF-8 sequence
Material user@vm-fruitbat:~$



I can "fix" it by saying:

	m[words[1].dup] = 1

But why does the original 'go wrong'



import std.stdio;
import std.string;
import std.stream;

void main()
{
	//Stream file = new File("test.txt");
        TArrayStream!(char[]) file =
		new TArrayStream!(char[])("newmtl one\nnewmtl two");

	int [char[]]	m;
	foreach(ulong line_no, ref string line; file) {
		string words[] = line.split();
      		m[words[1]] = 1; 	
	}
        foreach (char[] k, ref int v; m) {
		writefln("Material %s", k);
	}
}
April 02, 2008
Spacen Jasset wrote:
> The program below does not print what it should, either using a File or the TArrayStream.
> 
> It prints this:
> 
> user@vm-fruitbat:~$ dmd t.d
> user@vm-fruitbat:~$ ./t
> Error: 4invalid UTF-8 sequence
> Material user@vm-fruitbat:~$
> 
[snip]
>     foreach(ulong line_no, ref string line; file) {
>         string words[] = line.split();
>               m[words[1]] = 1;        }
>         foreach (char[] k, ref int v; m) {
>         writefln("Material %s", k);
>     }
> }

File.opApply (which is called by foreach), as implemented in superclass Stream, re-uses a (stack-allocated) buffer for each iteration. This is more efficient, but means the string put into the loop variable is only valid for that iteration; if you want to keep it beyond that you need to allocate a copy.
This is mentioned in the documentation for InputStream[1]: "The string passed in line may be reused between calls to the delegate."


[1] <http://www.digitalmars.com/d/1.0/phobos/std_stream.html>, search for "opApply".
April 02, 2008
Frits van Bommel wrote:
> Spacen Jasset wrote:
>> The program below does not print what it should, either using a File or the TArrayStream.
>>
>> It prints this:
>>
>> user@vm-fruitbat:~$ dmd t.d
>> user@vm-fruitbat:~$ ./t
>> Error: 4invalid UTF-8 sequence
>> Material user@vm-fruitbat:~$
>>
> [snip]
>>     foreach(ulong line_no, ref string line; file) {
>>         string words[] = line.split();
>>               m[words[1]] = 1;        }
>>         foreach (char[] k, ref int v; m) {
>>         writefln("Material %s", k);
>>     }
>> }
> 
> File.opApply (which is called by foreach), as implemented in superclass Stream, re-uses a (stack-allocated) buffer for each iteration. This is more efficient, but means the string put into the loop variable is only valid for that iteration; if you want to keep it beyond that you need to allocate a copy.
> This is mentioned in the documentation for InputStream[1]: "The string passed in line may be reused between calls to the delegate."
> 
> 
> [1] <http://www.digitalmars.com/d/1.0/phobos/std_stream.html>, search for "opApply".
I see ok. This is all very subtle though. Is my solution adding a .dup the best way or can I do something else?
April 03, 2008
Spacen Jasset wrote:
> I see ok. This is all very subtle though. Is my solution adding a .dup the best way or can I do something else?

If you need the string after the iteration of the loop in which it was bound, .dup is the best way to do so. (The original gets overwritten, so make a copy if you need it later -- not rocket science ;) )


Unless you're using D2-series compiler, in which case .idup may be better (especially for use as AA keys).