You ignore my bug report for a long time.
A item lost when casting a multiset to array!!!!
mapping special_attrs=([]);
void main() { multiset from=(<>); array _to=({(<"Stone","1","%70">),(<"Stone","2","%70">)}); multiset to; array rate=({}); int sum;
foreach(_to,multiset m){ int found; foreach(m;string k;int one){ if(k[0]=='%'){ int n; sscanf(k,"%%%d",n); rate+=({n}); sum+=n; m[k]=0; found=1; break; } } if(!found){ rate+=({1}); sum+=1; } } //int r=random(sum); int r=80; for(int i=0;i<sizeof(rate);i++){ if(r<rate[i]){ to=_to[i]; break; }else{ r-=rate[i]; } }
multiset unchanged=from&to; multiset special_add=(to-unchanged)&(multiset)(indices(special_attrs)); multiset special_del=(from-unchanged)&(multiset)(indices(special_attrs)); multiset direct_del=filter(from-unchanged,lambda(string x){if(x[0]!='!') return 1;else return 0;}); multiset direct_add=to-unchanged-special_add; werror("direct_add=%O\n",(direct_add)); werror("BUT (array)direct_add=%O\n",(array)(direct_add));
}
Output:
direct_add=(< /* 1 element */ "Stone", "2"
)
BUT (array)direct_add=({ /* 1 element */ "2" })
On Fri, Jul 07, 2006 at 06:36:42PM +0800, 郭雪松 wrote:
A item lost when casting a multiset to array!!!!
direct_add=(< /* 1 element */ "Stone", "2"
)
BUT (array)direct_add=({ /* 1 element */ "2" })
which version of pike is that?
i don't get the error with Pike v7.6 release 24 on debian/sarge but i do get it with Pike v7.6 release 61 on ubuntu/dapper
greetings, martin.
C:\Documents and Settings\ibm\����>pike --version Pike v7.6 release 66 Copyright ?1994-2005 Link�ping University Pike comes with ABSOLUTELY NO WARRANTY; This is free software and you are welcome to redistribute it under certain conditions; Read the files COPYING and COPYRIGHT in the Pike distribution for more details.
Windows XP
[root@sg1 root]# pike --version Pike v7.6 release 24 Copyright ?1994-2004 Link�ping University Pike comes with ABSOLUTELY NO WARRANTY; This is free software and you are welcome to redistribute it under certain conditions; Read the files COPYING and COPYRIGHT in the Pike distribution for more details.
[root@sg1 dev]# cat /etc/redhat-release Red Hat Linux release 9 (Shrike)
-----�ʼ�ԭ��----- ������: Martin B?hr [mailto:mbaehr@email.archlab.tuwien.ac.at] ����ʱ��: 2006��7��7�� 18:56 �ռ���: ��ѩ�� ����: pike-devel@lists.lysator.liu.se ����: Re: bug report: casting to array mistake of multiset
On Fri, Jul 07, 2006 at 06:36:42PM +0800, ��ѩ�� wrote:
A item lost when casting a multiset to array!!!!
direct_add=(< /* 1 element */ "Stone", "2"
)
BUT (array)direct_add=({ /* 1 element */ "2" })
which version of pike is that?
i don't get the error with Pike v7.6 release 24 on debian/sarge but i do get it with Pike v7.6 release 61 on ubuntu/dapper
greetings, martin.
That's probably because your bug example wasn't minimized enough. And as it has a call to random, it doesn't even always break. I've minimized it a bit, but more work could be done.
void main() { array _to=({ (<"Stone","1","%70">), (<"Stone","2","%70">) });
foreach(_to, multiset m) { foreach(m;string k;int one){ if(k=="%70") { m[k]=0; break; } } }
multiset direct_add=_to[1]-(<>);
werror("%O %O\n\n", (array)direct_add, direct_add); }
got it down to this:
void main() { multiset m=(<"Stone","2","%70">); foreach(m;string k;int one) { if(k=="%70") { m[k]=0; break; } }
multiset direct_add=m-(<>); werror("%O %O\n\n", (array)direct_add, direct_add); }
without the foreach, the error disappears...
greetings, martin.
Thank you. Fixes are checked in into all applicable versions.
Indeed it helps a lot to have a small test case. Anyway, I never saw the previous report since I didn't keep track of this forum during the winter months (was in Australia). Do we have a bug tracker somewhere nowadays (besides the old Crunch at community.roxen.com)?
for the curious,
could you explain what caused this bug?
and is there a way to work around this for affected versions, or do we need to wait for a new release?
greetings, martin.
It was a quirky special case where the size calculation got wrong when a mapping data block was copied in some functions. It's necessary to get deleted but still remembered entries (aka T_DELETED) on the internal free list in the data block for this to happen (see comment blurb near the top of multiset.h).
That typically happens when you have an active iterator (which you do in a foreach) for a multiset and delete elements in it at the same time. For some reason a break statement is necessary to keep the multiset in that state. I didn't investigate why that is so.
aha, thanks, so a workaround could be to avoid deletion in in a multiset while it is being iterated over:
void main() { multiset m=(<"Stone","2","%70">); multiset deletes=(<>); foreach(m;string k;int one) { if(k=="%70") { deletes[k]=1; break; } }
foreach(deletes;string k;) { m[k]=0; }
multiset direct_add=m-(<>); werror("%O %O\n\n", (array)direct_add, direct_add); }
Yes, or you can iterate over a copy if you want to delete items:
multiset m=(<"Stone","2","%70">); foreach(m + (<>);string k;int one) { if(k=="%70") { m[k]=0; break; } }
multiset direct_add=m-(<>); werror("%O %O\n\n", (array)direct_add, direct_add);
Can be slower, but it's less code.
pike-devel@lists.lysator.liu.se