<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!-- ===================================================================== -->
<!--  File:       SmallAdditionsToIOStream.html                            -->
<!--  Author:     J. Kanze                                                 -->
<!--  Date:       05/03/2007                                               -->
<!--      Copyright (c) 2007 James Kanze                                   -->
<!-- _____________________________________________________________________ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"/>
  <meta http-equiv="content-language" content="en"/>
  <meta name="author" content="J. Kanze"/>
  <meta name="date" content="2007-03-05T16:32:13MET"/>
  <meta name="generator" content="vim"/>
  <title>Some Small Additions to iostream</title>
  <style type="text/css">
    <!--
    .added { color:darkcyan; text-decoration:underline; }
    .removed { color:red; text-decoration:line-through; }
    .clause { padding-left:5em; }
    .hlabel { padding-right:1em; text-align:right; }
    -->
  </style>
</head>
<body>
<h1>Some Small Additions to iostream</h1>
<p>
<table rules="none" style="margin-left:60%">
  <tr><td class="hlabel">Doc. no.:</td><td>N2186=07-0046</td></tr>
  <tr><td class="hlabel">Date:</td><td>2007-03-06</td></tr>
  <tr><td class="hlabel">Author:</td><td>James Kanze</td></tr>
  <tr><td class="hlabel">email:</td><td><a href="mailto:james.kanze@gmail.com">james.kanze@gmail.com</a></td></tr>
</table>
</p>
<hr>
<h2>Require <tt>&lt;iostream&gt;</tt> to include
  <tt>&lt;istream&gt;</tt> and <tt>&lt;ostream&gt;</tt></h2>
<h3>Motivation and scope</h3>
<p>
  In practice, in most if not all implementations of the standard
  library, the header <tt>&lt;iostream&gt;</tt> includes
  <tt>&lt;istream&gt;</tt> and <tt>&lt;ostream&gt;</tt>, and probably
  some other files.  Many programmers have grown used to this, and
  aren't even aware that it isn't standard.  Many books also just
  include <tt>&lt;iostream&gt;</tt>, and suppose that the
  <tt>&lt;&lt;</tt> and <tt>&gt;&gt;</tt> operators will be available.
  Regardless of the original intent of the committee, or even my
  personal preferences (which would be for a very lightweight
  <tt>&lt;iostream&gt;</tt>), vendors will continue to have
  <tt>&lt;iostream&gt;</tt> include <tt>&lt;istream&gt;</tt> and
  <tt>&lt;ostream&gt;</tt>, because that's what users expect, and users
  will continue to believe that this is standard, because that's what
  all of the vendors do.  In this case, it is probably best if the
  standard just align itself with reality, and require what everyone
  already does.
</p>
<h3>What should be included</h3>
<p>
  The headers <tt>&lt;istream&gt;</tt> and <tt>&lt;ostream&gt;</tt>,
  obviously.  In practice, it's hard to imagine an implementation in
  which these didn't include <tt>&lt;ios&gt;</tt>, and most people would
  probably expect things like <tt>std::ios_base::badbit</tt> to be
  available whenever <tt>std::istream</tt> or <tt>std::ostream</tt> is,
  so we might as well say it explicitly.
</p>
<p>
  I'm less sure with regards to <tt>&lt;streambuf&gt;</tt>, but it seems
  likely that most implementations already include it, since the
  template sources for most of the <tt>&lt;&lt;</tt> and
  <tt>&gt;&gt;</tt> operators require it.  Thus, requiring it doesn't
  seem to add any real overhead, and doing so may prevent an occasional
  surprise.
</p>
<p>
  I see no particular need for including any of the other headers.
  <tt>&lt;iosfwd&gt;</tt> is subsumed in part by
  <tt>&lt;istream&gt;</tt> and <tt>&lt;ostream&gt;</tt>, and the other
  parts don't seem to be expected.  <tt>&lt;sstream&gt;</tt> and
  <tt>&lt;fstream&gt;</tt> add functionality that typically isn't
  expected by people only using <tt>&lt;iostream&gt;</tt>, and they
  aren't included by most current implementations either.  The case of
  <tt>&lt;iomanip&gt;</tt> is less clear cut&mdash;I don't think I've
  ever used <tt>&lt;ostream&gt;</tt> without it, if only for
  <tt>std::setw()</tt>, but since most current implementations don't
  include it either, I'd say that we should leave it out as well.
</p>
<h3>Proposed text</h3>
<p>
  In [iostream.objects]:
</p>
<blockquote>
  <p>
  <b>Header <tt>&lt;iostream&gt;</tt> synopsis</b>
  <pre>
    <span class="added">#include &lt;ios&gt;</span>
    <span class="added">#include &lt;streambuf&gt;</span>
    <span class="added">#include &lt;istream&gt;</span>
    <span class="added">#include &lt;ostream&gt;</span>

    namespace std {
      extern istream cin;
      extern ostream cout;
      extern ostream cerr;
      extern ostream clog;
      extern wistream wcin;
      extern wostream wcout;
      extern wostream wcerr;
      extern wostream wclog;
        }
  </pre>
  </p>
  <p>
    The header <tt>&lt;iostream&gt;</tt> declares objects that associate
    objects with the standard C streams provided for by the functions
    declared in <tt>&lt;cstdio&gt;</tt><span class="added">, and includes
    all of the headers neccesary to use these objects</span>.
  </p>
</blockquote>
<hr>
<h2>Support for &lt;&lt; and &gt;&gt; for extended integral types</h2>
<h3>Motivation and scope</h3>
<p>
  The standard now provides for extended integral types.  It would be
  nice if the user were able to read and write them, as well as
  declaring variables of the type.  And it is impossible to write such
  code oneself without knowing which typedef's correspond to standard
  types, and which ones correspond to extended types.
</p>
<h3>Proposed text</h3>
<p>
  This depends somewhat on other proposals.  If concepts make it in, and
  it is possible to restrict a template to instantiations which are
  integral types, then replacing <tt>&lt;&lt;</tt> and <tt>&gt;&gt;</tt>
  with a single template, restricted to integral types, might be an
  option.  Otherwise...
</p>
<p>
  In [istream], in the class definition:
</p>
<blockquote>
  <pre>
    basic_istream&lt;charT,traits&gt;&amp; operator&gt;&gt;(bool&amp; n);
    basic_istream&lt;charT,traits&gt;&amp; operator&gt;&gt;(short&amp; n);
    <i>[...]</i>
    basic_istream&lt;charT,traits&gt;&amp; operator&gt;&gt;(double&amp; f);
    basic_istream&lt;charT,traits&gt;&amp; operator&gt;&gt;(long double&amp; f);
    <span class="added">// <i>In addition, the implementation shall provide overloads of &gt;&gt;</i></span>
    <span class="added">// <i>for all extended integral types, with the same semantics</i></span>
    <span class="added">// <i>as those for the standard integral types</i></span>
  </pre>
</blockquote>
<p>
  and in [ostream], in the class definition:
</p>
<blockquote>
  <pre>
    basic_ostream&lt;charT,traits&gt;&amp; operator&lt;&lt;(bool n);
    basic_ostream&lt;charT,traits&gt;&amp; operator&lt;&lt;(short n);
    <i>[...]</i>
    basic_ostream&lt;charT,traits&gt;&amp; operator&lt;&lt;(double f);
    basic_ostream&lt;charT,traits&gt;&amp; operator&lt;&lt;(long double f);
    <span class="added">// <i>In addition, the implementation shall provide overloads of &lt;&lt;</i></span>
    <span class="added">// <i>for all extended integral types, with the same semantics</i></span>
    <span class="added">// <i>as those for the standard integral types</i></span>
  </pre>
</blockquote>
<p>
  Note that this really implies some work in [locale.num.get] and
  [locale.nm.put] as well; they should support at least the types
  <tt>intmax_t</tt> and <tt>uintmax_t</tt>, if these are larger than
  <tt>long long</tt> and <tt>unsigned long long</tt>.
</p>
<hr>
<h2>Provide access to the underlying file descriptor in <tt>filebuf</tt></h2>
<h3>Motivation and scope</h3>
<p>
  Almost all systems are capable of doing more with files than is
  supported by <tt>std::filebuf</tt>; most are also capable of treating
  other types of objects like files, once they have been constructed.
  Typical examples include locking, synchronized access, or reading and
  writing pipes or sockets.  These functionalities are not universal,
  and it is not proposed to add them in any way to the standard, but it
  does seem reasonable to make it possible for the user to access them,
  without foregoing the standard types for what they do support.  The
  idea is thus to simple make the underlying type used to identify the
  open file known to the user, by means of a typedef, and to provide
  functions for reading this identifier from an open
  <tt>std::filebuf</tt>, and associating such an identifier to an
  p<tt>std::filebuf</tt>.
</p>
<p>
  Note that when a user associates such an identifier to a
  <tt>std::filebuf</tt>, the file is considered open, unless the
  identifier has a special predefined value meaning closed.  When the
  user makes such an association, it is his responsibility to open and
  close the file; the function <tt>std::filebuf::close</tt> cannot be
  used, and it is undefined behavior to call it.  (It is expected that
  implementations on platforms such as Unix or Windows, where the system
  level close works for such identifiers, even when they do not identify
  an actual file, the implementor will support
  <tt>std::filebuf::close</tt> for such file identifiers, as an
  extention.  I'm not sure that this is the case of all systems,
  however, and I can easily imagine systems where a different system
  request would be used to close such an object.)
</p>

<h3>Proposed text</h3>
<p>
  In [fstreams]
</p>
<blockquote>
  <p>
    The header <tt>&lt;fstream&gt;</tt> defines four class templates and
    eight types that associate stream buffers with files and assist
    reading and writing files.
  </p>
  <p>
  <b>Header <tt>&lt;fstream&gt;</tt> synopsis</b>
  </p>
  <pre>
    namespace std {
      <span class="added">typedef <i>implementation defined</i> native_file_descriptor;</span>
      <span class="added">const native_file_descriptor invalid_file_descriptor;</span>

      template &lt;class charT, class traits = char_traits&lt;charT&gt; &gt;
        class basic_filebuf;
      typedef basic_filebuf&lt;char&gt; filebuf;
      typedef basic_filebuf&lt;wchar_t&gt; wfilebuf;

      template &lt;class charT, class traits = char_traits&lt;charT&gt; &gt;
        class basic_ifstream;
      typedef basic_ifstream&lt;char&gt; ifstream;
      typedef basic_ifstream&lt;wchar_t&gt; wifstream;
      
      template &lt;class charT, class traits = char_traits&lt;charT&gt; &gt;
        class basic_ofstream;
      typedef basic_ofstream&lt;char&gt; ofstream;
      typedef basic_ofstream&lt;wchar_t&gt; wofstream;

      template &lt;class charT, class traits = char_traits&lt;charT&gt; &gt;
        class basic_fstream;
        typedef basic_fstream&lt;char&gt; fstream;
        typedef basic_fstream&lt;wchar_t&gt; wfstream;
      }
  </pre>
</blockquote>
<p>
  In [filebuf]
</p>
<blockquote>
  <pre>
  namespace std {
    template &lt;class charT, class traits = char_traits&lt;charT&gt; &gt;
    class basic_filebuf : public basic_streambuf&lt;charT,traits&gt; {
    public:
      
      <i>[...]</i>
      // 27.8.1.3 Members:
      bool is_open() const;
      <span class="added">native_file_descriptor file_descriptor() const;</span>
      basic_filebuf&lt;charT,traits&gt;* open(const char* s ,
          ios_base::openmode mode);
      basic_filebuf&lt;charT,traits&gt;* open(const string&amp; s ,
          ios_base::openmode mode);
      <span class="added">basic_filebuf&lt;charT,traits&gt;* open( native_file_descriptor n) ;</span>
      basic_filebuf&lt;charT,traits&gt;* close();
      
    protected: 
      // 27.8.1.4 Overridden virtual functions:
      <i>[...]</i>
    };
  }
  </pre>
</blockquote>
<p>
  In [filebuf.members], add or modify the following descriptions of functions:
</p>
<blockquote>
  <pre>
    <span class="added">native_file_descriptor file_descriptor() const;</span>
  </pre>
  <p class="clause">
  <span class="added"><i>Returns:</i> the native file descriptor. This
    value is guaranteed to be the same as
    <tt>invalid_file_descriptor</tt> if <tt>!is_open()</tt>, otherwise,
    the value is implementation defined (but should allow the user to
    make calls to the OS API which affect the same underlying file in
    the system).</span>
  </p>
  <pre>
    <span class="added">basic_filebuf&lt;charT,traits&gt;* open(native_file_descriptor n, ios_base::openmode mode);</span>
  </pre>
  <p class="clause">
    <span class="added"><i>Effects:</i> If
    <tt>is_open()&nbsp;!=&nbsp;false</tt>, returns a null pointer.
    Otherwise, initializes the filebuf as required.  It then treats
    <i>n</i> as if it were the return value of the system level open
    which would have been performed for the <i>mode</i> parameter.  If
    <i>n</i> corresponds to a legal file descripter in the native OS,
    the open operation is deemed to have succeeded, otherwise, it is
    deemed to have failed.</span>
  </p>
  <p class="clause">
    <span class="added"><i>Returns:</i> <tt>this</tt> if successful, a
    null pointer otherwise.</span>
  </p>
  <pre>
    basic_filebuf&lt;charT,traits&gt;* close();
  </pre>
  <p class="clause">
    <i>Effects:</i> If <tt>is_open()&nbsp;==&nbsp;false</tt>, returns a
    null pointer. If a put area exists, calls
    <tt>overflow(traits::eof())</tt> to flush characters.  If the last
    virtual member function called on <tt>*this</tt> (between
    <tt>underflow</tt>, <tt>overflow</tt>, <tt>seekoff</tt>, and
    <tt>seekpos</tt>) was <tt>overflow</tt> then calls
    <tt>a_codecvt.unshift</tt> (possibly several times) to determine a
    termination sequence, inserts those characters and calls
    <tt>overflow(traits::eof())</tt> again. Finally <span
    class="added">if the file was opened by one of the <tt>open</tt>
    functions taking a string as argument,</span> it closes the file (as
    if by calling <tt>std::fclose(file))</tt>. If any of the calls to
    <tt>overflow</tt> or <tt>std::fclose</tt> fails then <tt>close</tt>
    fails. <span class="added">Sets the native file descripter to an
    invalid value.</span>
  </p>
  <p class="clause">
    <i>Returns:</i> <tt>this</tt> on success, a null pointer otherwise.
  </p>
  <p class="clause">
    <i>Postcondition:</i> <tt>is_open() == false</tt>.
  </p>
</blockquote>
<hr>
<h2>Provide mutexes for iostream objects</h2>
<h3>Motivation and scope</h3>
<p>
  This may be a bit premature, but if, as seems likely, threads are
  added to the standard, users will want to be able to lock the standard
  iostream objects, particularly <tt>std::cerr</tt>, in order to do
  things like:
  <pre>
    std::cerr &lt;&lt; "value = " &lt;&lt; value &lt;&lt; std::endl ;
  </pre>
  safely.  In this case, of course, "users" may include library authors,
  which makes it almost impossible for the user to establish a global
  mutex object for the entire application.  Given this, there is
  definite advantage in providing this in the standard.
</p>
<h3>Proposed solution</h3>
<p style="font-style:italic">
  (In the following, please consider <tt>std::mutex</tt> as as stand-in
  for any type of locking object that the committee finally adopts.)
</p>
<p>
  My first consideration is that <tt>std::ios_base</tt> should
  <strong>not</strong> contain a <tt>std::mutex</tt> object.  Most
  iostream objects (at least in my code) do not need it, so it is a cost
  which would frequently be paid when not needed.  I also do not like
  the idea of the standard iostream objects being somehow special.  And
  I rather prefer that the locking be explicit; just locking the
  individual <tt>&lt;&lt;</tt> and <tt>&gt;&gt;</tt> operators isn't
  usually necessary, and when it is, it usually isn't sufficient, since
  the granularity is too low.  With this in mind, I propose a global
  function which returns a mutex associated with the stream:
  <pre>
    std::mutex&amp; stream_lock( std::ios_base&amp; ) ;
  </pre>
  (No guarantee that different streams have different mutexes, but a
  guarantee that two calls with the same stream return the same mutex.)
  The main goal here is to support things like:
  <pre>
     std::mutex::scoped_lock l( stream_lock( std::cerr ) ) ;
     std::cerr &lt;&lt; ...
  </pre>
</p>
<p>
  Formally, just having a single mutex and always returning it would be
  conforming.  I would encourage implementations, however, to use lazy
  creation of the mutexes, with some sort of map, and with the
  destructor of <tt>std::ios_base</tt> ensuring that the mutex was
  correctly destructed, if it had been created.
</p>

</body>
</html>
<!-- Local Variables:               === for emacs -->
<!-- mode: sh                       === for emacs -->
<!-- tab-width: 8                   === for emacs -->
<!-- End:                           === for emacs -->
<!-- vim: set ts=8 filetype=html:   === for vim   -->
