From: Peter Olcott on
On 5/31/2010 9:16 PM, Joseph M. Newcomer wrote:
> See below...
> On Mon, 31 May 2010 20:16:53 +0200, "Giovanni Dicanio"
> <giovanniDOTdicanio(a)REMOVEMEgmail.com> wrote:
>
>> "Joseph M. Newcomer"<newcomer(a)flounder.com> wrote:
>>
>>>> UTF8.reserve(UTF32.size() * 4); // worst case
>>> ****
>>> Note that this will call malloc(), which will involve setting a lock, then
>>> searching for a
>>> block to allocate, then releasing the lock. Since you have been a fanatic
>>> about
>>> performance, why is it you put a very expensive operation like 'reserve'
>>> in your code?
>>>
>>> While it is perfectly reasonable, it seems inconsistent with your
>>> previously-stated goals.
>>
>> Joe: I'm not sure if you are ironic or something :) ... but I believe that
>> std::vector::reserve() with a proper capacity value, followed by several
>> push_back()s, is very efficient.
>> Sure, not as efficient as a static stack-allocated array, but very
>> efficient.
> ****
> But this code was written by someone who has been beating us nearly insensible about how
> critical every single instruction is. So the code shown takes more instructions than
> other alternatives, and he's been telling us that alternative implementations that take an
> extra instuction or two are unacceptable implementations. So this code is inconsistent
> with his previous concerns about performance.
>
> If there is irony here, it is the fact that he violates his own strongly-stated goals
> about perfomance, I could not help but point out the inconsistency.

My designs are the fastest possible designs. The implementations of
these designs are not encoded to be the fastest possible encoding. I
design the fastest code, and implement the most readable code. This was
stated in my original specification but you missed it. I could say that
missing such an important detail is pretty stupid, but I won't.

By the way the single implementation choice of using a sentinel and
gotos instead of a loop by itself produced 50% faster code. I am
considering discarding this because requiring a NULL terminator seems a
little too clumsy.

> *****
>>
>>
>>> No, the CORRECT way to write such code is to either throw an exception (if
>>> you are in C++,
>>> which you clearly are) or return a value indicating the error (for
>>> example, in C, an
>>
>> In this case, I'm for exception.
>> Thanks to exception, you could use the precious function return value to
>> actually return the resulting buffer (UTF8 string), instead of passing it as
>> a reference to the function:
> ****
> I'd probably choose to throw an exception, where the exception information included the
> offset into the input vector, a pointer to the input vector so the handler could decide
> what to do, etc.
> ****

This is far too cumbersome in developmental code. Once the code has
shown to be correct, then these sorts of enhancements can be made to
derive production quality code.

>>
>> // Updated prototype:
>> // - use 'const' correctness for utf32
>> // - return resulting utf8
>> // - may throw on error
>> std::vector<uint8_t> toUTF8(const std::vector<uint32_t> & utf32);
>>
>> Note that thanks to the move semantics (i.e. the new "&&" thing of C++0x,
>> available in VC10 a.k.a. VS2010), you don't pay for extra useless copies in
>> returning potentially big objects.
> ****
> Yep. But this did not state it was a 2010-compliant version. Ultimately, there is a
> philosophical inconsistency between his strongly-stated concerns about performance over
> the last several months, and the actual implmentation presented here. Since he loves
> picking nits with us, I felt it was only fair to return the favor.
>
> This does not change the fact that the printf is without a doubt a really awful interface.
> joe

NOT for developmental code. It requires less effort, thus less time to
validate that the code is correct. Because of this alternatives to
printf (for the purpose of validating code) tend to be inferior.

> ****
>>
>> Giovanni
>>
>>
> Joseph M. Newcomer [MVP]
> email: newcomer(a)flounder.com
> Web: http://www.flounder.com
> MVP Tips: http://www.flounder.com/mvp_tips.htm

From: Peter Olcott on
On 6/1/2010 5:52 AM, Oliver Regenfelder wrote:
> Hello,
>
> Leigh Johnston wrote:
>> Also printf sucks, this is a C++ newsgroup not a C newsgroup.
>
> This is not even a general C++ newsgroup but an MFC one. So
> strictly there is zero relevance of his posting to this
> newsgroup.
>
> Best regards,
>
> Oliver

So no one using MFC (such as I) would ever need to decode UTF-8?
From: Joseph M. Newcomer on
See below...
On Tue, 01 Jun 2010 08:51:05 -0500, Peter Olcott <NoSpam(a)OCR4Screen.com> wrote:

>On 5/31/2010 9:16 PM, Joseph M. Newcomer wrote:
>> See below...
>> On Mon, 31 May 2010 20:16:53 +0200, "Giovanni Dicanio"
>> <giovanniDOTdicanio(a)REMOVEMEgmail.com> wrote:
>>
>>> "Joseph M. Newcomer"<newcomer(a)flounder.com> wrote:
>>>
>>>>> UTF8.reserve(UTF32.size() * 4); // worst case
>>>> ****
>>>> Note that this will call malloc(), which will involve setting a lock, then
>>>> searching for a
>>>> block to allocate, then releasing the lock. Since you have been a fanatic
>>>> about
>>>> performance, why is it you put a very expensive operation like 'reserve'
>>>> in your code?
>>>>
>>>> While it is perfectly reasonable, it seems inconsistent with your
>>>> previously-stated goals.
>>>
>>> Joe: I'm not sure if you are ironic or something :) ... but I believe that
>>> std::vector::reserve() with a proper capacity value, followed by several
>>> push_back()s, is very efficient.
>>> Sure, not as efficient as a static stack-allocated array, but very
>>> efficient.
>> ****
>> But this code was written by someone who has been beating us nearly insensible about how
>> critical every single instruction is. So the code shown takes more instructions than
>> other alternatives, and he's been telling us that alternative implementations that take an
>> extra instuction or two are unacceptable implementations. So this code is inconsistent
>> with his previous concerns about performance.
>>
>> If there is irony here, it is the fact that he violates his own strongly-stated goals
>> about perfomance, I could not help but point out the inconsistency.
>
>My designs are the fastest possible designs.
****
By the use of reserve() and push_back(), the code you show is not the fastest possible
*code*. I don't care about designs; designs are not executable!
****
>The implementations of
>these designs are not encoded to be the fastest possible encoding. I
>design the fastest code, and implement the most readable code. This was
>stated in my original specification but you missed it. I could say that
>missing such an important detail is pretty stupid, but I won't.
****
You really miss the point here. How could a *design* that requires an allocation be
construed as something which could have an implementation that is the fastest possible
code? Therefore, the design is not a design which lends itself to a fast encoding. If
you had designed code to be fast, you would not have required the use of reserve() or
push_back in the code!

*You* were the one that insisted that designs include the final code, not me!

A design that was intended to result in the fastest possible code would not include a
requirement of a call to a storage allocator. So I can only assume that the design was,
by your odd definition, not the "fastest possible" design. But I don't really care about
designs; you showed an actual *code* artifact, and that is the ONLY thing that can be
judged for its speed. Designs don't execute; code executes, and therefore the only thing
you presented is a less-than-ideal implementation in terms of raw performance.
****
>
>By the way the single implementation choice of using a sentinel and
>gotos instead of a loop by itself produced 50% faster code. I am
>considering discarding this because requiring a NULL terminator seems a
>little too clumsy.
****
What is the problem with adding a NUL terminator (it is spelled NUL, with one L; that is
the official designation of the 0 character in both ANSI and Unicode)? It is one
push_back at the end.

Remember, you can design so that if you return prematurely, the validity of the output
buffer is undefined.
joe
****
>
>> *****
>>>
>>>
>>>> No, the CORRECT way to write such code is to either throw an exception (if
>>>> you are in C++,
>>>> which you clearly are) or return a value indicating the error (for
>>>> example, in C, an
>>>
>>> In this case, I'm for exception.
>>> Thanks to exception, you could use the precious function return value to
>>> actually return the resulting buffer (UTF8 string), instead of passing it as
>>> a reference to the function:
>> ****
>> I'd probably choose to throw an exception, where the exception information included the
>> offset into the input vector, a pointer to the input vector so the handler could decide
>> what to do, etc.
>> ****
>
>This is far too cumbersome in developmental code. Once the code has
>shown to be correct, then these sorts of enhancements can be made to
>derive production quality code.
>
>>>
>>> // Updated prototype:
>>> // - use 'const' correctness for utf32
>>> // - return resulting utf8
>>> // - may throw on error
>>> std::vector<uint8_t> toUTF8(const std::vector<uint32_t> & utf32);
>>>
>>> Note that thanks to the move semantics (i.e. the new "&&" thing of C++0x,
>>> available in VC10 a.k.a. VS2010), you don't pay for extra useless copies in
>>> returning potentially big objects.
>> ****
>> Yep. But this did not state it was a 2010-compliant version. Ultimately, there is a
>> philosophical inconsistency between his strongly-stated concerns about performance over
>> the last several months, and the actual implmentation presented here. Since he loves
>> picking nits with us, I felt it was only fair to return the favor.
>>
>> This does not change the fact that the printf is without a doubt a really awful interface.
>> joe
>
>NOT for developmental code. It requires less effort, thus less time to
>validate that the code is correct. Because of this alternatives to
>printf (for the purpose of validating code) tend to be inferior.
>
>> ****
>>>
>>> Giovanni
>>>
>>>
>> Joseph M. Newcomer [MVP]
>> email: newcomer(a)flounder.com
>> Web: http://www.flounder.com
>> MVP Tips: http://www.flounder.com/mvp_tips.htm
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
See below..,
On Tue, 01 Jun 2010 08:38:24 -0500, Peter Olcott <NoSpam(a)OCR4Screen.com> wrote:

>On 5/31/2010 9:10 PM, Joseph M. Newcomer wrote:
>> See below...
>> On Mon, 31 May 2010 12:17:00 -0500, Peter Olcott<NoSpam(a)OCR4Screen.com> wrote:
>>
>>> I am not that concerned with performance. The number one priority is
>>> readability and maintainability. Performance is secondary to this.
>> ****
>> But in all your previous posts, you were declaring that the real value of a DFA was that
>> it was the fastest possible implementation. Suddenly, performance no longer matters.
>
>No you merely screwed up yet again and misread what I said. You screw up
>in this way quite often. This is your biggest single mistake. Your
>second biggest mistake is gross over exaggeration.
>
>As one example: You said that nothing can be known about the efficiency
>of a method without testing. I have empirically proven this statement
>completely false. I accurately predicted exactly how much another UTF8
>decoder would be than my own code using the simple heuristic of
>estimating the number of machine instructions in the execution path. 50%
>more instructions did indeed result in 50% more time.
****
Funny, I don't recall seeing the experimental results that demonstrated that. Results
computed using QueryPerformanceCounter, showing the mean and standard deviation of a large
number of experiments.

Oh, and I don't recall you showing the code generated by that example, or giving potential
instruction counts across a distribution of 1, 2, 3 and 4-byte encodings. Or even giving
us data to indicate how many > 1-byte encodings you were handling. You are free to prove
me wrong (you did it once, already, and I accept the data you collected), but without
evidence, I am entitled to offer my opinion about the code, based on my considerable
experience in writing, debugging, measuring, and generating machine code.

Note: I have been an expert witness. When I am asked my "expert opinion" I am expected to
give an opinion based upon my expertise. Such an opinion cannot be construed as libelous,
because libel implies that I know the statement to be untrue. Look at case law on libel.
But then again, I do have a certificate on Forensic Science and the Law from a local very
important law school, and we had to study tort law as part of that. This means we had to
understand what is meant by "libel" and what is meant by "expert". It would only be
libel if I lied about what my experience had taught me, and said a statement inconsistent
with my experience. My experience tells me that reserve() is a Really Bad Idea if your
purpose is raw performance. My experience tells me that doing error reporting directly in
a utility subroutine is poor design. Therefore, I am offering expert opinion based on my
experience, and consistent with my experience.
****
>
>>
>> And I still think the design is abysmal from a viewpoint of performance, usability,
>> flexibility, and error reporting. Anyone who chooses to, in a general-purpose subroutine,
>> pop up a MessageBox or do a printf, is simply clueless about how to design good software.
>> ****
>
>I already warned you that such statements are libelous and that you
>should cease and desist such statements. No one else here had indicated
>that the design is less than good.
****
Well, that might be because no one else spent 15 years doing performance measurement of
programs. I look for little details, like the use of reserve() and push_back().

I was not aware that others had to agree with me to make a statement about code quality
"non-libelous". In fact, you have no proof that using reserve() is zero cost, whereas I
know how storage allocators work and know that its cost is always nonzero, and potentially
very large (depending on how malloc is implemented), so making a statement to that effect
is factual, not libelous.
****
>
>>>> From the bits viewpoint, it is probably correct (I didn't work out all lthe shifts and
>>>> masks, figuring you probably got those right) but from a design and architecture
>>>> viewpoint, it is truly awful code given the stated goals. Besides limiting it to console
>>>
>>> That statement could be libelous. Cease and desist any such commentary.
>> ****
>> What statement? That it is awful code given the stated goals? That can't be libelous.
>
>Do you really want to risk it?
****
But the facts indicate otherwise. For my statement to be untrue, you would have to
demonstrate that reserve() had zero cost, always. That push_back was faster than
incrementing a target index and storing through it, under all conditions. Have you
demonstrated this?
****.
>
>>> It is by no means truly awful code, anyone that knows code well would
>>> know this. Prospective future employers might not know code well enough,
>>> and believe what you said.
>> ****
>> Sorry, I would not hire someone who was dumb enough to put a printf in a piece of code
>> that could be used in a Windows environment, or even in a console environment.
>
>Since no one else here thinks that my code is anything like abysmal that
>shows that there is something else going on besides an objective
>assessment of the quality of my code.
****
OK, show the set of performance measurements, using a high-resolution timer, and showing
how many experiments you ran, and the mean and standard deviation. Perferably for a
variety of input length strings, say 100 characters, 1000 characters and 10,000
characters. This is how science is done. Telling me that your implementation is the
fastest possible implementation when, in fact, it is potentially abysmal (do you know the
potential cost of that reserve()? What if it takes a single page fault while searching
the heap for a block of the right size?), is not "evidence".

If you said "Here's an example of code" that's one thing. But promising us for weeks that
you were going to implement something that was the fastest possible realization of an
algorithm and then not actually showing that is inconsistent. Defending your "design" by
a less-than-fastest-possible implementation is not "evidence".
joe
****
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Joseph M. Newcomer on
See below...
On Mon, 31 May 2010 13:49:07 -0500, Peter Olcott <NoSpam(a)OCR4Screen.com> wrote:

>On 5/31/2010 1:16 PM, Giovanni Dicanio wrote:
>> "Joseph M. Newcomer" <newcomer(a)flounder.com> wrote:
>>
>>>> UTF8.reserve(UTF32.size() * 4); // worst case
>>> ****
>>> Note that this will call malloc(), which will involve setting a lock,
>>> then searching for a
>>> block to allocate, then releasing the lock. Since you have been a
>>> fanatic about
>>> performance, why is it you put a very expensive operation like
>>> 'reserve' in your code?
>>>
>>> While it is perfectly reasonable, it seems inconsistent with your
>>> previously-stated goals.
>>
>> Joe: I'm not sure if you are ironic or something :) ... but I believe
>> that std::vector::reserve() with a proper capacity value, followed by
>> several push_back()s, is very efficient.
>> Sure, not as efficient as a static stack-allocated array, but very
>> efficient.
>
>He needed to find some excuse to denigrate my code. He has had a
>personal grudge against me for several months. I don't really know what
>I said to offend him, but, it must have occurred sometime after he sung
>very high praises about my patent a few months ago.
***
I do not have a "personal grudge against you"; what I dislike are people who are
pretentious, who make statements they can't back up, and present code that is inconsistent
with their loudly-touted goals and try to make claims that it is the best possible code
when it is not.

I defended you against what I thought was an *unfair* accusation, that of being a Patent
Troll. If there are unjust accusations, I will object. But when you batter us to
insensibility about how critical performance is, and talk about presenting the "fastest
possible design", then I am equally offended; designs cannot be executed and therefore
cannot have speed. Code has measurable performance. And the code presented was bad code,
for all the reasons I stated. It has nothing to do with a personal grudge; it has
entirely to do with the fact that you state one thing, then present as evidence of your
correctness something which contradicts your own statement. This is not consistent.
Therefore, it is a target of opportunity to point out that you are not making sense. I
also have to judge code for its correctness not just in the core algorithm, but in the
overall implementation; utility code which uses printf or which even interacts with the
user is not correct code, because it either will not work at all or will produce
meaningless output to the user, and neither of these represent an acceptable design.

If you make sense, I will defend you. If you prove me wrong with actual numbers, I will
accept your numbers and agree that you are actually right. I did once before. But if you
offer opnions on the performance of artficats that are measurable (code, not designs),
without the data to back them, then you are not making sense, and you need to be told
this.
joe
..
****
>
>>> No, the CORRECT way to write such code is to either throw an exception
>>> (if you are in C++,
>>> which you clearly are) or return a value indicating the error (for
>>> example, in C, an
>>
>
>The "correct" way to handle an error when testing code for the first
>time is to use a printf() statement, or other easy to use debugging
>construct. When the code moves to production, then either of the other
>two suggestions may be appropriate.
>
>> In this case, I'm for exception.
>> Thanks to exception, you could use the precious function return value to
>> actually return the resulting buffer (UTF8 string), instead of passing
>> it as a reference to the function:
>>
>> // Updated prototype:
>> // - use 'const' correctness for utf32
>> // - return resulting utf8
>> // - may throw on error
>> std::vector<uint8_t> toUTF8(const std::vector<uint32_t> & utf32);
>
>For most compilers this requires making an extra copy.
>
>>
>> Note that thanks to the move semantics (i.e. the new "&&" thing of
>> C++0x, available in VC10 a.k.a. VS2010), you don't pay for extra useless
>> copies in returning potentially big objects.
>>
>> Giovanni
>>
>>
>>
>Counting on this results in code that does not have the same performance
>characteristics across multiple platforms.
Joseph M. Newcomer [MVP]
email: newcomer(a)flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm