C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

wrapping a stream interface
Goto page 1, 2  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated)
View previous topic :: View next topic  
Author Message
John Dill
Guest





PostPosted: Wed Sep 17, 2003 9:30 am    Post subject: wrapping a stream interface Reply with quote



I have a logging system which takes a string and a message type in a
singleton of the form

1: Log::Singleton::Instance().Log( ERROR, "Error Message" );

However, this becomes a little cumbersome to use when sending numbers
or user defined data. I was wondering what the best strategy to wrap
stream insertion semantics around a class of the form

2: Log<ERROR>::Singleton::Instance() << "Error Message" << value <<
etc...

I know that using a ostringstream would be the best way to go, but how
to implement the interface. Should I inherit from ostringstream,
encapsulate. I think I will need to rewrite all the insertion
operators so that they send text to my logging singleton through the
interface used in 1, which tends towards encapsulation.

Also with respect to user-defined types, most of them have operators
which allows them to be printed to an ostream. Would I have to
duplicate this interface for my logging stream classes? Can this be
generalized on stream type? Is it recommended to do so?

I've also seen macros which contain insertion operations of the form
(in itk/vtk for instance)

3: ErrorMacro( << "Error Message" << value );

which wrap logging with an ostringstream in this particular way, but I
don't like it very much.

Any suggestions, examples?

Thanks,
John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Samuel Krempp
Guest





PostPosted: Wed Sep 17, 2003 7:58 pm    Post subject: Re: wrapping a stream interface Reply with quote



le Wednesday 17 September 2003 11:30, [email]john-dill (AT) uiowa (DOT) edu[/email] écrivit :

Quote:
2: Log<ERROR>::Singleton::Instance() << "Error Message" << value
etc...

I know that using a ostringstream would be the best way to go, but how
to implement the interface.

the interface you seem to suggest is fine :
std::ostream& Log
Quote:
Should I inherit from ostringstream,
encapsulate. I think I will need to rewrite all the insertion
operators so that they send text to my logging singleton through the
interface used in 1, which tends towards encapsulation.

the stream system is adequately designed to encapsulate your particular
logging code inside a streambuf.
If it is possible to have your Instance() function return a stringstream&,
then it's the easiest (but then you need to dump the stringstream to your
destination at some point.)

But it's much more flexible to make your own streambuf, inheriting
basic_ios<char>
It's quite easy too, though you have to know what to define to have it
operate correctly. (overflow and xsputn are the key functions for a buffer
designed for output, you can have them move the buffer chars to a
destination function)
Making a streambuf is a FAQ, you should be able to find many detailed
explanations on that.

Quote:
Also with respect to user-defined types, most of them have operators
which allows them to be printed to an ostream. Would I have to
duplicate this interface for my logging stream classes? Can this be
generalized on stream type? Is it recommended to do so?

if you encapsule your logging system in a streambuf, used inside a stream,
user-defined types output will work just as well as if it was std::cout.

--
Samuel.Krempp
cout << "@" << "crans." << (is_spam ? "trucs.en.trop." : "" )
<< "ens-cachan.fr" << endl;


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Aaron Bentley
Guest





PostPosted: Wed Sep 17, 2003 8:06 pm    Post subject: Re: wrapping a stream interface Reply with quote



John Dill wrote:

Quote:
I have a logging system which takes a string and a message type in a
singleton of the form

1: Log::Singleton::Instance().Log( ERROR, "Error Message" );

However, this becomes a little cumbersome to use when sending numbers
or user defined data. I was wondering what the best strategy to wrap
stream insertion semantics around a class of the form

2: Log<ERROR>::Singleton::Instance() << "Error Message" << value
etc...

Some people seem to get very upset at the notion of using << and >> for
anything other than streams. So remember, you can also do

Log<ERROR>::Singleton::Instance().Log("Error Message").Log(value) etc.

However, I don't see how you're separating log entries. It looks like
you might get:

--log.txt------------
ERROR "Error Message"
ERROR value
---------------------

Instead, you might want something like
Log<ERROR>::Singleton::Instance().Entry().Log("Error Message").Log(value)

Quote:
I know that using a ostringstream would be the best way to go, but how
to implement the interface. Should I inherit from ostringstream,
encapsulate.

AFAICT, ostringstream is an implementation detail, so you should not
inherit from it. In theory, you could implement it with snprintf, right?

Quote:
Also with respect to user-defined types, most of them have operators
which allows them to be printed to an ostream. Would I have to
duplicate this interface for my logging stream classes? Can this be
generalized on stream type? Is it recommended to do so?

As a default, you can have

template <typename T>
Log::operator << (T const &userdefined)
{
this->mystream << userdefined;
}


Quote:

I've also seen macros which contain insertion operations of the form
(in itk/vtk for instance)

3: ErrorMacro( << "Error Message" << value );

which wrap logging with an ostringstream in this particular way, but I
don't like it very much.

It does have the advantage of clearly separating log entries, though.

HTH

--
Aaron Bentley
www.aaronbentley.com

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Ulrich Eckhardt
Guest





PostPosted: Wed Sep 17, 2003 8:10 pm    Post subject: Re: wrapping a stream interface Reply with quote

John Dill wrote:
Quote:
2: Log<ERROR>::Singleton::Instance() << "Error Message" << value
etc...

I know that using a ostringstream would be the best way to go, but how
to implement the interface. Should I inherit from ostringstream,
encapsulate. I think I will need to rewrite all the insertion
operators so that they send text to my logging singleton through the
interface used in 1, which tends towards encapsulation.

// hopefully a bit of inspiration for you
enum errorclass{info, warning, error};
struct log: ostringstream
{
log(errorclass a): m_ec(a){}
~log()
{
Log::singleton().write( m_ec, this->str());
}
errorclass m_ec;
};
log(info) << "ph00barrn";


A different approach would be to simply templatize the log-function, using a
stringstream to assemble the different number of arguments into a string. I
usually only log a few (<10) values, that is a thing to hack together in a
few minutes or even automatize, since it is all the same code.

Uli


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Dietmar Kuehl
Guest





PostPosted: Thu Sep 18, 2003 9:37 am    Post subject: Re: wrapping a stream interface Reply with quote

[email]john-dill (AT) uiowa (DOT) edu[/email] (John Dill) wrote:
Quote:
Any suggestions, examples?

The way to go is, of course, to derive a stream buffer which writes to your
logging mechanism at appropriate points. Actually, the most difficult part
about this issue is to decide when to sent stuff to the logging mechanism.
My personal preference is to set up the stream buffer to detect line ends
and to sent the buffer collected so far then. An alternative is to use a
special manipulator, eg. "endlog", to sent the stuff or to use the
destructor of an appropriate temporary object. Here is a short version
which is untested but should give yout the general idea:

struct logbuf: std::streambuf {
logbuf(): m_level(ERROR) {}
~logbuf() { flush(); }
void set_log_level(int level) { m_level = level; }
private:
int_type overflow(int_type i) {
if (!traits_type::eq_int_type(i, traits_type::eof())) {
char_type c = traits_type::to_char_type(i);
if (c == 'n')
flush();
else
m_buffer.push_back(c);
}
return traits_type::not_eof(i);
}
void flush() {
Log::Singleton::Instance().Log(level, m_buffer);
m_buffer.clear();
}

std::string m_buffer;
};

You would then use this stream buffer with an 'std::ostream' object
initialized to use this stream buffer. To ease it's creation it is likely
that you would create an appropriate derived class, eg.:

struct logstream_pbase { logbuf m_sbuf; };
class logstream: logstream_pbase, public std::ostream {
logstream(): std::ios(&m_sbuf), std::ostream(&m_sbuf) {}
void set_log_level(int level) { m_sbuf.set_log_level(level); }
};

The logging level could then be set using a manipulator or it may be
appropriately initialized in the constructor.

Of course, there is no need to implement any of the overloaded output
operators: this is the reason for the stream buffer layer of the IOStreams
system in the first place...
--
<mailto:dietmar_kuehl (AT) yahoo (DOT) com> <http://www.dietmar-kuehl.de/>
Phaidros eaSE - Easy Software Engineering: <http://www.phaidros.com/>

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Dill
Guest





PostPosted: Fri Sep 19, 2003 10:02 am    Post subject: Re: wrapping a stream interface Reply with quote

I want to thank all of you for your suggestions and I will definitely
look into the streambuf possibility. In the passing time, I tried to
generate a stream class which wraps around std::ostringstream which
does a lot of what I want, but still looking at other possibilities.
If you have time to critique it, it would be helpful since I've not
done anything like this before.

One thing that I didn't mention specifically is that this log system
tries to generalize the output destination, whether is be an ostream,
a fstream, or maybe even a socket stream, which is configurable in the
MessageDispatcher class (it's a bit more complicated than that, but
that's the general idea). I mimicked a buffered output for how I am
sending text to the MessageDispatcher. I also ran into a little kink
because of differences in iostream libraries between gcc 2.95 series
and 3.

The one issue is that I would like to be able to apply std::endl,
std::flush, std::ends to somehow flush the text to MessageDispatcher,
and empty the buffer, but all of those take std::ostream.

Here is my (imcomplete) version:

/*!
* class MessageStream message_stream.hpp
* brief A message stream implements the insertion operators but
instead
* of sending them to the screen, sends them to the message
dispatcher.
*/
class MessageStream
: private NonCopyable
{

//! The self type.
typedef MessageStream Self;

public:

//! The singleton type.
typedef uiro::SingletonHolder<MessageStream, uiro::DefaultLifetime,
uiro::CreateStatic> Singleton;

//! Initializes the ostringstream.
MessageStream()
{ MessageDispatcher::Singleton::Instance(); }

//! Destructor which does nothing.
~MessageStream()
{}

Self& operator<<( long n )
{ oss_ << n; return *this; }

Self& operator<<( float n )
{ oss_ << n; return *this; }

Self& operator<<( double n )
{ oss_ << n; return *this; }

// implement other operator<<'s

Self& operator<<( Self& (*pf)( Self& ) )
{ return (*pf)(*this); }

#if 0
Self& operator<<( std::ios& (*pf)( std::ios& ) )
{ oss_ << pf; return *this; }
#endif

#if 1
Self& operator<<( std::ios_base& (*pf)( std::ios_base& ) )
{ oss_ << pf; return *this; }
#endif

Self& put( char c )
{ oss_.put( c ); return *this; }

Self& flush()
{
oss_.flush();
// This will be templatized once working for a single enum type
message_dispatcher::Instance().Log( INFO, oss_.str() );
oss_.str( std::string() );
return *this;
}

template friend inline Self& operator<<( Self& ms, const Manipulator& m )
{ ms.oss_ << m; return ms; }

private:

//! The message dispatcher type.
typedef MessageDispatcher::Singleton message_dispatcher;

std::ostringstream oss_;

};


namespace lsm {

MessageStream& endl( MessageStream& ms )
{ ms.put( 'n' ); return ms.flush(); }

MessageStream& ends( MessageStream& ms )
{ ms.put( '' ); return ms.flush(); }

MessageStream& flush( MessageStream& ms )
{ return ms.flush(); }

}

Suggestions, critiques welcome.

Thanks,
John

P.S. I use google groups and find myself erasing the whole text I am
writing without being able to undo the erase due to my nervous
repetitive vi ESC hitting. Anyone have a solution, other than get
mental help :)

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
Attila Feher
Guest





PostPosted: Fri Sep 19, 2003 10:16 am    Post subject: Re: wrapping a stream interface Reply with quote

Aaron Bentley wrote:
[SNIP]
Quote:
AFAICT, ostringstream is an implementation detail, so you should not
inherit from it. In theory, you could implement it with snprintf,
right?

Note: snprintf is not part of the current C++ standard (as far as I know).

It is part of the C99 standard, but its signature is (AFAIU) incompatible
with C++, because it contains restrict-ed pointers.

Of course, many (if not all) C++ implementation have snprintf, but it is
still worth to note that they are not required to.

--
Attila aka WW



[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Fri Sep 19, 2003 10:23 am    Post subject: Re: wrapping a stream interface Reply with quote

[email]john-dill (AT) uiowa (DOT) edu[/email] (John Dill) wrote in message
news:<302c79f4.0309160726.47a50e4e (AT) posting (DOT) google.com>...
Quote:
I have a logging system which takes a string and a message type in a
singleton of the form

1: Log::Singleton::Instance().Log( ERROR, "Error Message" );

However, this becomes a little cumbersome to use when sending numbers
or user defined data. I was wondering what the best strategy to wrap
stream insertion semantics around a class of the form

2: Log<ERROR>::Singleton::Instance() << "Error Message" << value
etc...

I know that using a ostringstream would be the best way to go, but how
to implement the interface. Should I inherit from ostringstream,
encapsulate. I think I will need to rewrite all the insertion
operators so that they send text to my logging singleton through the
interface used in 1, which tends towards encapsulation.

Also with respect to user-defined types, most of them have operators
which allows them to be printed to an ostream. Would I have to
duplicate this interface for my logging stream classes? Can this be
generalized on stream type? Is it recommended to do so?

Dietmar and Samuel have given simple solutions that work well in
practice. I've occasionally used something a bit more complex,
particularly when I wanted to support log entries with more than one
line (and thus needed to know when each entry started) or wanted to
support multithreading (with the important point of not interleaving
output in different entries from different threads): basically, I create
a wrapper class for the ostreams involved, with its own templated
operator<<, which checks if logging is active, and formats and forwards
to the final destination only if it is.

The key to making this work is pseudo-value semantics along with some
sort of instance counting -- the idea is that the Log function returns
an instance (which will result in a copy), which becomes a temporary,
and the destructor of the temporary releases the lock, or ensures that
the entry ends with a new line, or sets a flag so that the next output
will be preceded by a complete log header, or whatever.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Dill
Guest





PostPosted: Sat Sep 20, 2003 9:57 am    Post subject: Re: wrapping a stream interface Reply with quote

[email]kanze (AT) gabi-soft (DOT) fr[/email] wrote in message news:<d6652001.0309180536.64c77bca (AT) posting (DOT) google.com>...
Quote:
Dietmar and Samuel have given simple solutions that work well in
practice. I've occasionally used something a bit more complex,
particularly when I wanted to support log entries with more than one
line (and thus needed to know when each entry started) or wanted to
support multithreading (with the important point of not interleaving
output in different entries from different threads): basically, I create
a wrapper class for the ostreams involved, with its own templated
operator<<, which checks if logging is active, and formats and forwards
to the final destination only if it is.

The key to making this work is pseudo-value semantics along with some
sort of instance counting -- the idea is that the Log function returns
an instance (which will result in a copy), which becomes a temporary,
and the destructor of the temporary releases the lock, or ensures that
the entry ends with a new line, or sets a flag so that the next output
will be preceded by a complete log header, or whatever.

I do like the streambuf idea as it interfaces with the user defined
ostream functions. I am still working on trying it out. I do also
want to make it mt-safe. One of my motivations is to provide a way to
trace through threads using TRACE type macros, but providing separate
keys for each trace so that the trace statements in different threads
don't intertwine (as long as they are written to separate files).

I have seen the problem with operator<< in a multithreading setting
mixing up the order, (not within operator<<, but in using multiple
insertions for the same line of text, ie std::cout << "The value is "
<< value << std::endl will often intermix the "text", value, and
'n'). Can this be solved within the context of an ostream or
streambuf wrapper without using external guards? I'm not convinced at
this point.

Would this locking proxy idea work with singletons? I return a
reference to an instance, and thus shouldn't make a temporary. Or
perhaps I'm not seeing where the temporary is made. Or would I have
to change my singleton class to return a proxy object? I'm using
Loki's SingletonHolder right now and I assume I would need to make
some change to a policy to get this type of behavior.

Thanks,
John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Dill
Guest





PostPosted: Mon Sep 22, 2003 10:40 pm    Post subject: Re: wrapping a stream interface Reply with quote

I have been looking into trying to get the stream interface
multi-threaded, and have run into the problem of where I would like to
lock the stream over several insertion operators. I am currently
using the MessageStream wrapper over a ostringstream at the moment,
and was wondering how best to synchronize multiple insertions, ie

MessageStream::Singleton::Instance() << "Var1 = " << var1 << ", Var2 =
" << var2 << std::endl << ms::endlog;

where ms::endlog is a stream manipulator for sending the text to the
MessageDispatcher system.

One way of doing this is wrapping all of this in a macro:

InfoMacro( << "Var1 = " << var1 << ... )

which expands to placing a {}'d guard to lock over that statement.

Another idea which I have is to use a stream manipulator to lock and
unlock the MessageStream, ie

MessageStream::Singleton::Instance() << ms::lock_stream << "Var1 = "
<< var1 << ", Var2 = " << var2 << std::endl << ms::endlog <<
ms::unlock_stream;

where these stream manipulators wrap locking and unlocking around all
the insertion operators.

Another option, but depends on how long the temporary variable's
lifetime is to have a stream manipulator guard where

MessageStream::Singleton::Instance() << ms::stream_guard << "Var1 = "
<< var1 << ", Var2 = " << var2 << std::endl << ms::endlog;

which would guard over the whole statement, but that depends on what
the life of the stream_guard would be. Can someone explain what the
length of any temporary object would be in a sequence of insertion
operations?

Thanks,
John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
James Kanze
Guest





PostPosted: Tue Sep 23, 2003 9:05 am    Post subject: Re: wrapping a stream interface Reply with quote

[email]john-dill (AT) uiowa (DOT) edu[/email] (John Dill) writes:

Quote:
kanze (AT) gabi-soft (DOT) fr wrote in message
news:<d6652001.0309180536.64c77bca (AT) posting (DOT) google.com>...
Dietmar and Samuel have given simple solutions that work well in
practice. I've occasionally used something a bit more complex,
particularly when I wanted to support log entries with more than
one line (and thus needed to know when each entry started) or
wanted to support multithreading (with the important point of not
interleaving output in different entries from different threads):
basically, I create a wrapper class for the ostreams involved,
with its own templated operator<<, which checks if logging is
active, and formats and forwards to the final destination only if
it is.

The key to making this work is pseudo-value semantics along with
some sort of instance counting -- the idea is that the Log
function returns an instance (which will result in a copy), which
becomes a temporary, and the destructor of the temporary releases
the lock, or ensures that the entry ends with a new line, or sets
a flag so that the next output will be preceded by a complete log
header, or whatever.

I do like the streambuf idea as it interfaces with the user defined
ostream functions. I am still working on trying it out. I do also
want to make it mt-safe. One of my motivations is to provide a way
to trace through threads using TRACE type macros, but providing
separate keys for each trace so that the trace statements in
different threads don't intertwine (as long as they are written to
separate files).

I have seen the problem with operator<< in a multithreading setting
mixing up the order, (not within operator<<, but in using multiple
insertions for the same line of text, ie std::cout << "The value is
" << value << std::endl will often intermix the "text", value, and
'n'). Can this be solved within the context of an ostream or
streambuf wrapper without using external guards? I'm not convinced
at this point.

Check out GB_OutputStreamWrapper at my site. It's a very generic
solution, designed for use in expressions along the lines of:

Log::instance()( severity ) << " blah, blah " << someInt ;

Basically, Log::severity returns a (temporary) GB_OutputStreamWrapper
(which of course, gets copied, as temporaries are wont to do). In the
constructor, it is passed a pointer to
GB_OutputStreamWrapper::LifetimeHandler; the GB_OutputStreamWrapper
calls the function "constructed" immediately, and the function
"destructed" when the last copy is destructed -- at the end of the full
expression here. All you need to do is for the Lifetime handler to
acquire the lock in "constructed", and release it in "destructed".

You can do a lot more -- my "constructed" function also works in
conjunction with the (filtering) streambuf of the output to inform it
that it is at the beginning of a single log entry -- the next character
output triggers a full header, with time stamp, etc., and following
that, the first character after a newline triggers a few blanks, to
indent. Similarly, my "destructed" function informs the streambuf,
which outputs a 'n' if we are not at the start of the line, and flushes
the buffer.

I've found the functionality useful in even more complicated cases.
Once or twice, for example, I have wanted to output a small table to the
log. In such cases, I do something like:

{
GB_OutputStreamWrapper output( Log::instance()( severity ) ) ;
output << "Table header:n" ;
for ( int i = 0 ; i < table.size() ; ++ i ) {
output << ... << n ;
}
}

Here, the LifetimeHandler maintains the lock for the entire table.

As for convincing you: look at the code. If you see some reason it
might not work, let me know. (Supposing a conforming compiler. I
currently have to work with Sun CC, for example, and nothing dependant
on the correct lifetime of temporaries works.

The generic solution at my site is somewhat heavy; you may prefer using
it as inspiration for a custom solution, rather than using it directly.

Quote:
Would this locking proxy idea work with singletons? I return a
reference to an instance, and thus shouldn't make a temporary.

The problem would be to know when to release the lock. The temporary is
the key to making it work -- you need the temporary so that its
destructor can be called at the end of the full expression.

Quote:
Or perhaps I'm not seeing where the temporary is made.

That *is* the tricky point, and it is what held me up a long time. The
key is to use a form of reference counting in the temporary, so it can
be freely copied. The constructor for orginal instance starts things
going; this instance and all of its copies are counted, and the
destructor of the last copy does the clean up.

Quote:
Or would I have to change my singleton class to return a proxy
object?

You need a proxy object. For logging, this isn't a problem, as shown
above. Typically, in fact, you will encapsulate my example in a
somewhat more complex macro, along the lines of:

#define LOG( severity )
Log::instance().getStream( __FILE__, __LINE__, severity )

Quote:
I'm using Loki's SingletonHolder right now and I assume I would need
to make some change to a policy to get this type of behavior.

Not really. The log is managed by a singleton. You call a function on
that singleton to get the proxy.

In small applications. In larger applications, I tend to use a static
local variable in each file, which enroles with the singleton proxy
manager. This allows adjusting the logging levels on a subsystem level,
rather than globally.

--
James Kanze mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France +33 1 41 89 80 93

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Dill
Guest





PostPosted: Wed Sep 24, 2003 1:12 pm    Post subject: Re: wrapping a stream interface Reply with quote

[email]john-dill (AT) uiowa (DOT) edu[/email] (John Dill) wrote in message news:<302c79f4.0309221420.2ac75dc4 (AT) posting (DOT) google.com>...

I'm just adding a little more description as reading it this morning
doesn't describe how I'm thinking that these solutions may work.

Quote:

Another idea which I have is to use a stream manipulator to lock and
unlock the MessageStream, ie

MessageStream::Singleton::Instance() << ms::lock_stream << "Var1 = "
var1 << ", Var2 = " << var2 << std::endl << ms::endlog
ms::unlock_stream;

where these stream manipulators wrap locking and unlocking around all
the insertion operators.

Let me explain the locking semantics of what this would do. There are
two objects, the MessageStream which wraps an ostringstream to do the
formatting, and a MessageDispatcher, to actually log the message.
Both can operate independently, and lock on access like normal to
their internal structures. In this scenario, the lock_stream is sent
first. It is a wrapper of a function object which locks the
MessageStream instance. Then, all the insertion operations can be
sent to the MessageStream without being interrupted due to the lock.
You get to ms::endlog. This needs to lock the MessageDispatcher so
that the MessageStream's data can be sent without intermixing with
other MessageStream's (which I'm still not sure if MessageStream
should be a singleton or not, so it's still a little up in the air).
ms::endlog would appear as

MessageDispatcher lock
send MessageStream stringstream text to MessageDispatcher
MessageDispatcher unlock

Then when all the Message has been sent, the ms::unlock_stream would
release the lock on the MessageStream object/singleton.

Quote:

Another option, but depends on how long the temporary variable's
lifetime is to have a stream manipulator guard where

MessageStream::Singleton::Instance() << ms::stream_guard << "Var1 = "
var1 << ", Var2 = " << var2 << std::endl << ms::endlog;

which would guard over the whole statement, but that depends on what
the life of the stream_guard would be. Can someone explain what the
length of any temporary object would be in a sequence of insertion
operations?


The way I envision this operating is that instead of operator<<
returning the same ostream instance, it returns a wrapper which has
locking semantics but has the same functionality as MessageStream.
You would specialize operator<< for the stream_guard something like
this

LockedMessageStream operator<<( MessageStream& ms, ms::stream_guard sg
)
{ return LockedMessageStream( *this ); }

where the constructor would take a reference to the MessageStream and
lock it. Then for the rest of the operator<<, it uses the
LockedMessageStream wrapper to perform the synchronized insertion
operations, then log to MessageDispatcher, then the temporary will go
out of scope unlocking the MessageStream. Of course this depends on
how the lifetime of the corresponding LockedMessageStream temporary
object works out.

Any thoughts?
John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
John Dill
Guest





PostPosted: Wed Sep 24, 2003 10:33 pm    Post subject: Re: wrapping a stream interface Reply with quote

Ah, I get the basic idea now. What suprised me though was that you
were returning a const reference instead of an object in ostream<<.
Where are the copies being made when you have a statement with
multiple insertions? In the above example, at what place does the
"temporary" come into existance. Or maybe if you just did

GB_OutputStreamWrapper( Log::instance()( severity ) ) << "blah = " <<
blah << ... << std::endl;

would this create a "temporary" that would go out of scope at the end
of the statement? I thought you were implying passing temporaries
using the return value of the ostream<< operator.

Thanks,
John

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Sep 25, 2003 3:44 pm    Post subject: Re: wrapping a stream interface Reply with quote

[email]john-dill (AT) uiowa (DOT) edu[/email] (John Dill) wrote in message
news:<302c79f4.0309240612.24641cc3 (AT) posting (DOT) google.com>...

Quote:
Ah, I get the basic idea now. What suprised me though was that you
were returning a const reference instead of an object in ostream<<.
Where are the copies being made when you have a statement with
multiple insertions?

In the original return statement. When you write something like:

return GB_OutputStreamWrapper( someOStream, handlerPtr ) ;

the formal semantics are to evaluate the expression (thus creating a
*local* temporary), then copy it into where ever the results go (which
obviously cannot be local). Compilers are allowed to elide the local
instance; I think some do, some don't. In any case, I prefer not to
count on it. More generally, anytime I'm dealing with return values or
pass by value parameters, I find the simplest thing is to just assume
that you have no idea how many instances may be created, or how often
the object may be copied.

Quote:
In the above example, at what place does the "temporary" come into
existance.

It depends on the compiler. Somewhere in the return statement of the
called function. The problem is that the temporary may be a copy, and
not the originally constructed value.

Quote:
Or maybe if you just did

GB_OutputStreamWrapper( Log::instance()( severity ) ) << "blah = "
blah << ... << std::endl;

If you do this, you don't need the reference counting. If you want to
count on it, you should declare a private copy constructor, to ensure
that you don't get copies.

Globally, I find the flexibility of allowing the copies useful, and I
don't find that the copying or the reference counting make a noticeable
difference in performance.

Quote:
would this create a "temporary" that would go out of scope at the end
of the statement?

Yes.

Quote:
I thought you were implying passing temporaries using the return
value of the ostream<< operator.

No. One could also do that, given the reference counting, but there's
no point in doing extra work for nothing.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
kanze@gabi-soft.fr
Guest





PostPosted: Thu Sep 25, 2003 8:48 pm    Post subject: Re: wrapping a stream interface Reply with quote

[email]john-dill (AT) uiowa (DOT) edu[/email] (John Dill) wrote in message
news:<302c79f4.0309230903.7b964e26 (AT) posting (DOT) google.com>...
Quote:
john-dill (AT) uiowa (DOT) edu (John Dill) wrote in message
news:<302c79f4.0309221420.2ac75dc4 (AT) posting (DOT) google.com>...

I'm just adding a little more description as reading it this morning
doesn't describe how I'm thinking that these solutions may work.

Another idea which I have is to use a stream manipulator to lock
and unlock the MessageStream, ie

MessageStream::Singleton::Instance() << ms::lock_stream << "Var1 = "
var1 << ", Var2 = " << var2 << std::endl << ms::endlog
ms::unlock_stream;

where these stream manipulators wrap locking and unlocking around
all the insertion operators.

Let me explain the locking semantics of what this would do. There are
two objects, the MessageStream which wraps an ostringstream to do the
formatting, and a MessageDispatcher, to actually log the message.

Why the ostringstream? My own solution uses a filtering streambuf for
this. Basically, the filtering streambuf contains a list of final
destinations, in the form of streambuf*.

Quote:
From your other responses, I gather that you've already looked at my
OutputStreamWrapper; for the streambuf, I use a variant of the

EventGeneratingOutputStream streambuf, with a common object for both the
LifetimeHandler and the EventHandler. This filtering streambuf feeds
into a second, which contains a list of streambuf* to the actual
destinations.

The basic scenario is this, supposing the user writes a macro:

LOG( severity ) << "Label: " << value :

This expands to something like:

Log::insatnce().getStream( severity, __FILE__, __LINE__ ) << ...

The log object contains a table of streambuf*, each of which points to
the second streambuf mentionned above (or NULL, if there is no tracing
for this level of severity). If the entry is NULL, getStream returns
immeidately with an GB_OutputStreamWrapper( NULL ). Otherwise, it
constructs the EventGeneratingOutputStream, forwarding to the
dispatching streambuf it found in the table, and passing it to the
constructor of the OutputStreamWrapper, which it then returns.

The combined handler gets the filename and the line number as parameter.
In the constructed function, it acquires the lock (in multithread mode).
In the startOfLine function, it outputs the header information
(timestamp, filename, linenumber), and marks the fact that this has been
output, further calls to startOfLine only output a number of spaces, for
intentation. In the destructed function, I call forceStartOfLine on the
streambuf, flushes the stream (which of course propagates down to the
final destination streambufs), and finally releases the lock.

As described above, this scenario results in a large number of objects
being allocated on each call to getStream. This has not been a problem
in my current uses; with a little bit of care, most of the objects could
be reused from one call to the next, however.

Quote:
Both can operate independently, and lock on access like normal to
their internal structures.

OK. This potentially allows some overlap between the generation of one
message, and the output of the following.

In a multithreaded environment, I'd do this by having the formatting
stream generate a string which it posted to a special thread, which
would handle the actual output.

Quote:
In this scenario, the lock_stream is sent first. It is a wrapper of a
function object which locks the MessageStream instance. Then, all the
insertion operations can be sent to the MessageStream without being
interrupted due to the lock. You get to ms::endlog. This needs to
lock the MessageDispatcher so that the MessageStream's data can be
sent without intermixing with other MessageStream's (which I'm still
not sure if MessageStream should be a singleton or not, so it's still
a little up in the air). ms::endlog would appear as

I don't think I'd use manipulators to do this. It's too easy for a
client to forget a manupulator. I definitely prefer my solution, which
depends on the lifetime of temporaries. (Of course, this, in turn,
causes problems for compilers like Sun CC, which don't implement the
standard lifetime of temporary rules.)

Quote:
MessageDispatcher lock
send MessageStream stringstream text to MessageDispatcher
MessageDispatcher unlock

Then when all the Message has been sent, the ms::unlock_stream would
release the lock on the MessageStream object/singleton.

Another option, but depends on how long the temporary variable's
lifetime is to have a stream manipulator guard where

MessageStream::Singleton::Instance() << ms::stream_guard << "Var1 = "
var1 << ", Var2 = " << var2 << std::endl << ms::endlog;

which would guard over the whole statement, but that depends on
what the life of the stream_guard would be. Can someone explain
what the length of any temporary object would be in a sequence of
insertion operations?

The way I envision this operating is that instead of operator
returning the same ostream instance, it returns a wrapper which has
locking semantics but has the same functionality as MessageStream.
You would specialize operator<< for the stream_guard something like
this

LockedMessageStream operator<<( MessageStream& ms, ms::stream_guard sg
)
{ return LockedMessageStream( *this ); }

That's what I do. Watch out for inadvertent copies. (See my other
post.)

Quote:
where the constructor would take a reference to the MessageStream and
lock it. Then for the rest of the operator<<, it uses the
LockedMessageStream wrapper to perform the synchronized insertion
operations, then log to MessageDispatcher, then the temporary will go
out of scope unlocking the MessageStream. Of course this depends on
how the lifetime of the corresponding LockedMessageStream temporary
object works out.

Again, the potential problem is that the client must intervene.

--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
11 rue de Rambouillet, 78460 Chevreuse, France, +33 (0)1 30 23 45 16

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ Language (Moderated) All times are GMT
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.