This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RE: Q about ctype.narrow


Jerry Quinn wrote:
> Pétur Runólfsson writes:
>  > Jerry Quinn wrote:
>  > > Here's the issue.  Assume we have ctype<char> that has been
> subclassed
>  > > by a library client.  Now:
>  > >
>  > > char ctype<char>::narrow(char c, char default)
>  > > {
>  > >   if (table[c]) return table[c];
>  > >   return table[c] = do_narrow(c, default);
>  > > }
>  >
>  > I don't think this is allowed under the as-if rule. (Calling a virtual
>  > function is an observable effect.)
> 
> I hope that's not required by the standard.  If so, it clobbers ANY
> optimization that caches values from virtual function calls.  You
> wouldn't be able to to cache widen results for numpunct fields, for
> example, since the spec says that the results have to be as if all the
> various do_widen's happened on a particular call.

No. There is a special exception in 22.1.1 p7 (modified by DR 360)
that allows users of locale to cache return values. Note that it
says "facet object installed in the same locale" so in:

ostream os(...);
os.widen('\n'); // Must call ctype::do_widen(char).
os.widen('\n'); // May use cached value.
os.imbue(os.getloc().combine<numpunct<char> >(locale("")));
// Same ctype facet, but different locale => must call
// ctype::do_widen again.
os.widen('\n'); 

The numpunct_cache meets this requirement, so it's OK. Also, since
only facets that are installed in locales are bound by this rule,
this would be OK, so long as this facet is never put in a locale:

class Qux : public ctype<char>
{
protected:
  char do_widen(char c) const { return (c + time(NULL)) % 256; }
};

There is also a problem if virtual members of facets are called
during construction. Consider this testcase:

class Foo : public ctype<char>
{
public:
  Foo() { widen('\n'); } // Calls Foo::do_widen('\n');
};

class Bar : public Foo
{
protected:
  char do_widen(char c) const { return ~c; }
};

Bar bar;
// Should return ~'\n', will return '\n' if the cache is in widen.
char c = bar.widen('\n');

These testcases are all somewhat silly, but IMHO so is any testcase
that overrides ctype<char>::do_widen or do_narrow. The best
optimization might actually be something like this:

const ctype<char>& ct = ...;
// Should be cached so that typeid is only called once:
bool trivial = (typeid(ct) == typeid(ctype<char>));
if (trivial)
  // Don't call narrow or widen
else
  // Call narrow and widen 

Regards,
Petur


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]