You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stdcxx.apache.org by se...@apache.org on 2006/06/21 03:48:31 UTC

svn commit: r415868 - in /incubator/stdcxx/trunk/include: fstream fstream.cc

Author: sebor
Date: Tue Jun 20 18:48:31 2006
New Revision: 415868

URL: http://svn.apache.org/viewvc?rev=415868&view=rev
Log:
2006-06-20  Martin Sebor  <se...@roguewave.com>

	STDCXX-7
	* fstream (xsputn): Declared.
	* fstream (xsputn): Overrode the base class virtual function and
	optimized to avoid unnecessary writes when the size of the array
	argument exceeds the amount of space available in the internal
	character buffer.
	(overflow): Moved most of the body of the function to xsputn()
	and called it.

Modified:
    incubator/stdcxx/trunk/include/fstream
    incubator/stdcxx/trunk/include/fstream.cc

Modified: incubator/stdcxx/trunk/include/fstream
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/include/fstream?rev=415868&r1=415867&r2=415868&view=diff
==============================================================================
--- incubator/stdcxx/trunk/include/fstream (original)
+++ incubator/stdcxx/trunk/include/fstream Tue Jun 20 18:48:31 2006
@@ -245,6 +245,10 @@
     // 27.8.1.4, p16 - in input mode, repopulates buffer from file
     virtual int sync ();
 
+    // overridden for efficiency
+    virtual _RWSTD_STREAMSIZE
+    xsputn (const char_type*, _RWSTD_STREAMSIZE);
+
 private:
 
     basic_filebuf*
@@ -259,7 +263,7 @@
 
     // write unshift sequence to file (multibyte, state-dependent encondings)
     bool _C_unshift ();
-    
+
     void      *_C_file;               // underlying FILE ptr or file descriptor
     pos_type   _C_cur_pos;            // offset/state in file corresponding to
                                       //  end of buffer, and actual pos in file 

Modified: incubator/stdcxx/trunk/include/fstream.cc
URL: http://svn.apache.org/viewvc/incubator/stdcxx/trunk/include/fstream.cc?rev=415868&r1=415867&r2=415868&view=diff
==============================================================================
--- incubator/stdcxx/trunk/include/fstream.cc (original)
+++ incubator/stdcxx/trunk/include/fstream.cc Tue Jun 20 18:48:31 2006
@@ -7,16 +7,22 @@
  *
  ***************************************************************************
  *
- * Copyright (c) 1994-2005 Quovadx,  Inc., acting through its  Rogue Wave
- * Software division. Licensed under the Apache License, Version 2.0 (the
- * "License");  you may  not use this file except  in compliance with the
- * License.    You    may   obtain   a   copy   of    the   License    at
- * http://www.apache.org/licenses/LICENSE-2.0.    Unless   required    by
- * applicable law  or agreed to  in writing,  software  distributed under
- * the License is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR
- * CONDITIONS OF  ANY KIND, either  express or implied.  See  the License
- * for the specific language governing permissions  and limitations under
- * the License.
+ * Copyright 2005-2006 The Apache Software Foundation or its licensors,
+ * as applicable.
+ *
+ * Copyright 1994-2006 Rogue Wave Software.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  * 
  **************************************************************************/
 
@@ -329,137 +335,199 @@
 
     this->setg (0, 0, 0);            // invalidate the get area
 
-    const char_type* __from_beg;     // pointer to start of sequence to write
-    const char_type* __from_end;     // pointer to end of sequence to write
+    const bool __unbuf = this->_C_is_unbuffered ();
 
     const char_type __c_to_char = traits_type::to_char_type (__c);
 
-    if (this->_C_is_unbuffered ()) {
-        __from_beg = &__c_to_char;
-        __from_end = __from_beg + 1;
+    if (this->pptr () == 0 && !__unbuf) {
+        // put area not valid yet - just need to initialize it
+        this->setp (this->_C_buffer, this->_C_buf_end ());
     }
-    else {
-        __from_beg = this->_C_buffer;
-        __from_end = this->pptr ();
+    else if (   this->pptr () == this->epptr ()
+             || this->_C_is_eof (__c)
+             || __unbuf) {
+
+        const char_type*  __buf;
+        _RWSTD_STREAMSIZE __nchars;
+
+        if (__unbuf) {
+            __buf    = &__c_to_char;
+            __nchars = 1;
+        }
+        else {
+            // call xsputn() with a special value to have it flush
+            // the controlled sequence to the file
+            __buf    = _RWSTD_REINTERPRET_CAST (char_type*, this);
+            __nchars = this->pptr () - this->pbase ();
+        }
+
+        if (__nchars != basic_filebuf::xsputn (__buf, __nchars))
+            return traits_type::eof ();  // error while writing
     }
 
-    if (this->pptr () == 0 && !this->_C_is_unbuffered ()) {
+    // now that there's room in the buffer, call sputc() recursively
+    // to actually place the character in the buffer (unless we're
+    // in unbuffered mode because we just wrote it out)
+    if (!this->_C_is_eof (__c) && !__unbuf)
+        this->sputc (__c_to_char);
+
+    this->_C_out_last (true);   // needed by close ()
+
+    return traits_type::not_eof (__c);
+}
+
+
+template <class _CharT, class _Traits>
+_RWSTD_STREAMSIZE
+basic_filebuf<_CharT, _Traits>::
+xsputn (const char_type* __buf, _RWSTD_STREAMSIZE __nchars)
+{
+    _RWSTD_ASSERT (0 != __buf || 0 == __nchars);
+    _RWSTD_ASSERT (this->_C_is_valid ());
+
+    if (0 == __nchars)
+        return 0;   // not an error
+
+    if (__nchars < 0 || !this->_C_is_out () || !is_open ())
+        return -1;   // error
+
+    if (0 == this->pptr () && !this->_C_is_unbuffered ())
         // put area not valid yet - just need to initialize it
         this->setp (this->_C_buffer, this->_C_buf_end ());
+
+    const _RWSTD_STREAMSIZE __navail = this->epptr () - this->pptr ();
+
+    const char_type* const __special =
+        _RWSTD_REINTERPRET_CAST (char_type*, this);
+
+    if (__buf == __special) {
+        __buf = this->pbase ();
     }
-    else if (   this->pptr () == this->epptr ()
-             || this->_C_is_eof (__c)
-             || this->_C_is_unbuffered ()) {
+    else if (__nchars <= __navail) {
+        // the amount of available space is big enough
 
-        //  flush put area to file,
-        //  performing code conversion if necessary
+        // append the contents of the buffer to the controlled sequence
+        traits_type::copy (this->pptr (), __buf, __nchars);
 
-        typedef _TYPENAME traits_type::state_type _StateT;
+        this->pbump (__nchars);
 
-        _RWSTD_STREAMSIZE __nwrote = 0;          // num chars to write
-        _StateT __state = _C_cur_pos.state ();   // state of stream
+        return __nchars;
+    }
+    else {
+        // call self recursively to flush the controlled sequence first
+        const _RWSTD_STREAMSIZE __nwrite = this->pptr () - this->pbase ();
 
-        _C_beg_pos = _C_cur_pos;
+        // return -1 on error to flush the controlled sequence
+        if (__nwrite != basic_filebuf::xsputn (__special, __nwrite))
+            return -1;
+    }
 
-        typedef codecvt<char_type, char, _StateT> _Codecvt;
+    //  flush buffer to file, performing code conversion if necessary
 
-        const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ());
+    _RWSTD_ASSERT (this->_C_is_valid ());
+    _RWSTD_ASSERT (this->_C_is_out ());
+    _RWSTD_ASSERT (is_open ());
 
-        if (__cvt.always_noconv ()) {
+    const char_type* const __end = __buf + __nchars;
 
-            // no conversion
+    typedef _TYPENAME traits_type::state_type _StateT;
 
-            __nwrote = __from_end - __from_beg;
+    _RWSTD_STREAMSIZE __nwrote = 0;          // num chars to write
+    _StateT __state = _C_cur_pos.state ();   // state of stream
 
-            const _RWSTD_STREAMSIZE __nbytes = sizeof (char_type) * __nwrote;
+    _C_beg_pos = _C_cur_pos;
 
-            if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state,
-                                              __from_beg, __nbytes))
-                return traits_type::eof ();  // error while writing
-        }
-        else {
+    typedef codecvt<char_type, char, _StateT> _Codecvt;
 
-            // conversion required: we do this a chunk at a time
-            // to avoid dynamic allocation of memory
+    const _Codecvt &__cvt = _USE_FACET (_Codecvt, this->getloc ());
 
-            char             __xbuf [_RWSTD_DEFAULT_BUFSIZE];
-            char*            __xbuf_end  = __xbuf + sizeof __xbuf;
-            char*            __to_next   = 0;
-            const char_type* __from_next = 0;
-
-            for (const char_type* __base = __from_beg;
-                 __from_next != __from_end;
-                 __base = __from_next) {
-
-                const codecvt_base::result __res =
-                    __cvt.out (__state, __base, __from_end, __from_next,
-                               __xbuf, __xbuf_end, __to_next);
+    if (__cvt.always_noconv ()) {
 
-                _RWSTD_STREAMSIZE __nbytes =
-                    sizeof (char_type) * (__from_end - __base);
+        // no conversion
 
-                switch (__res) {
-                case codecvt_base::error:
-                    // write out the sequence successfully converted up
-                    // to the point of the error in the internal sequence
-                    // and fail
-                    _RW::__rw_fwrite (_C_file, this->_C_state,
-                                      __base, __nbytes);
-                    return traits_type::eof ();
+        __nwrote = __end - __buf;
 
-                case codecvt_base::noconv:
-                    // write the entire sequence
-                    if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state,
-                                                      __base, __nbytes))
-                        return traits_type::eof ();
+        const _RWSTD_STREAMSIZE __nbytes = sizeof (char_type) * __nwrote;
 
-                    __nwrote += __from_end - __base
-                        + _C_crlf_intern_count (__base, __from_end);
+        if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state,
+                                          __buf, __nbytes))
+            return -1;  // error while writing
+    }
+    else {
 
-                    __from_next = __from_end; // effectively 'break'
-                    break;
+        // perform codeset conversion in chunks to avoid dynamic
+        // memory allocation
 
-                default:
-                    _RWSTD_ASSERT (   codecvt_base::ok == __res
-                                   || codecvt_base::partial == __res);
+        char             __xbuf [_RWSTD_DEFAULT_BUFSIZE];
+        char*            __xbuf_end  = __xbuf + sizeof __xbuf;
+        char*            __to_next   = 0;
+        const char_type* __from_next = 0;
+
+        for (const char_type* __base = __buf; __from_next != __end;
+             __base = __from_next) {
+
+            const codecvt_base::result __res =
+                __cvt.out (__state, __base, __end, __from_next,
+                           __xbuf, __xbuf_end, __to_next);
+
+            _RWSTD_STREAMSIZE __nbytes =
+                sizeof (char_type) * (__end - __base);
+
+            switch (__res) {
+            case codecvt_base::error:
+                // write out the sequence successfully converted up
+                // to the point of the error in the internal sequence
+                // and fail
+                _RW::__rw_fwrite (_C_file, this->_C_state, __base, __nbytes);
+                    return traits_type::eof ();
 
-                    // a partial conversion will result if there's
-                    // not enough space in the conversion buffer to
-                    // hold the converted sequence, but we're O.K.
-                    // since we'll be passing any remaining unconverted
-                    // characters (starting at __from_next) in the next
-                    // iteration
-
-                    __nbytes = __to_next - __xbuf;
-
-                    if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state,
-                                                      __xbuf, __nbytes))
-                        return traits_type::eof ();
+            case codecvt_base::noconv:
+                // write the entire sequence
+                if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state,
+                                                  __base, __nbytes))
+                    return traits_type::eof ();
 
-                    __nwrote += __nbytes
-                        + _C_crlf_extern_count (__xbuf, __to_next);
-                }
+                __nwrote += __end - __base
+                    + _C_crlf_intern_count (__base, __end);
+
+                __from_next = __end; // effectively 'break'
+                break;
+
+            default:
+                _RWSTD_ASSERT (   codecvt_base::ok == __res
+                               || codecvt_base::partial == __res);
+
+                // partial conversion will result if there isn't enough
+                // space in the conversion buffer to hold the converted
+                // sequence, but we're O.K. since we'll be passing any
+                // remaining unconverted characters (starting at
+                // __from_next) in the next iteration
+
+                __nbytes = __to_next - __xbuf;
+
+                if (__nbytes != _RW::__rw_fwrite (_C_file, this->_C_state,
+                                                  __xbuf, __nbytes))
+                    return -1;
+
+                __nwrote += __nbytes
+                    + _C_crlf_extern_count (__xbuf, __to_next);
             }
         }
-
-        // adjust the current position in the file
-        _C_cur_pos += __nwrote;
-        _C_cur_pos.state (__state);
-
-        // reset the put area
-        if (!this->_C_is_unbuffered ())
-            this->setp (this->_C_buffer, this->_C_buf_end ());
     }
 
-    // now that there's room in the buffer, call sputc() recursively
-    //  to actually place the character in the buffer (unless we're
-    //   in unbuffered mode because we just wrote it out)
-    if (!this->_C_is_eof (__c) && !this->_C_is_unbuffered ())
-        this->sputc (__c_to_char);
+    // adjust the current position in the file
+    _C_cur_pos += __nwrote;
+    _C_cur_pos.state (__state);
+
+    // reset the put area
+    if (!this->_C_is_unbuffered ())
+        this->setp (this->_C_buffer, this->_C_buf_end ());
 
     this->_C_out_last (true);   // needed by close ()
 
-    return traits_type::not_eof (__c);
+    // return the number of characters (not bytes) in the buffer
+    // successfully written to the file
+    return __nchars;
 }