$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r83689 - in branches/release: boost libs/conversion libs/conversion/doc libs/conversion/test
From: antoshkka_at_[hidden]
Date: 2013-04-01 16:40:44
Author: apolukhin
Date: 2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
New Revision: 83689
URL: http://svn.boost.org/trac/boost/changeset/83689
Log:
Merge from trunk:
* Fix stream related issues with libc++ and clang (fixes #7704, fixes #8267)
* Change runtime assert to compile time when converting to pointer (fixes #8267)
Added:
   branches/release/libs/conversion/test/lexical_cast_filesystem_test.cpp   (contents, props changed)
   branches/release/libs/conversion/test/lexical_cast_to_pointer_test.cpp   (contents, props changed)
Text files modified: 
   branches/release/boost/lexical_cast.hpp                |   150 +++++++++++++++++++++++++++++---------- 
   branches/release/libs/conversion/doc/lexical_cast.qbk  |     4                                         
   branches/release/libs/conversion/lexical_cast_test.cpp |    10 --                                      
   branches/release/libs/conversion/test/Jamfile.v2       |     2                                         
   4 files changed, 117 insertions(+), 49 deletions(-)
Modified: branches/release/boost/lexical_cast.hpp
==============================================================================
--- branches/release/boost/lexical_cast.hpp	(original)
+++ branches/release/boost/lexical_cast.hpp	2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
@@ -173,6 +173,7 @@
 #include <boost/math/special_functions/fpclassify.hpp>
 #include <boost/range/iterator_range_core.hpp>
 #include <boost/container/container_fwd.hpp>
+#include <boost/integer.hpp>
 #ifndef BOOST_NO_CWCHAR
 #   include <cwchar>
 #endif
@@ -1414,23 +1415,97 @@
 #endif 
     }
 
-    namespace detail // stl_buf_unlocker
+    namespace detail // parser_buf
     {
-        template< class BufferType, class CharT >
-        class stl_buf_unlocker: public BufferType{
+        //
+        // class parser_buf:
+        // acts as a stream buffer which wraps around a pair of pointers
+        //
+        // This class is copied (and slightly changed) from
+        // boost/regex/v4/cpp_regex_traits.hpp
+        // Thanks John Maddock for it! (previous version had some
+        // problems with libc++ and some other STL implementations)
+        template <class BufferType, class charT>
+        class parser_buf : public BufferType {
+           typedef BufferType base_type;
+           typedef typename base_type::int_type int_type;
+           typedef typename base_type::char_type char_type;
+           typedef typename base_type::pos_type pos_type;
+           typedef ::std::streamsize streamsize;
+           typedef typename base_type::off_type off_type;
+
         public:
-            typedef BufferType base_class;
+           parser_buf() : base_type() { setbuf(0, 0); }
+           const charT* getnext() { return this->gptr(); }
 #ifndef BOOST_NO_USING_TEMPLATE
-            using base_class::pptr;
-            using base_class::pbase;
-            using base_class::setg;
-            using base_class::setp;
+            using base_type::pptr;
+            using base_type::pbase;
 #else
-            CharT* pptr() const { return base_class::pptr(); }
-            CharT* pbase() const { return base_class::pbase(); }
-            void setg(CharT* gbeg, CharT* gnext, CharT* gend){ return base_class::setg(gbeg, gnext, gend); }
-            void setp(CharT* pbeg, CharT* pend) { return setp(pbeg, pend); }
+            charT* pptr() const { return base_type::pptr(); }
+            charT* pbase() const { return base_type::pbase(); }
 #endif
+           base_type* setbuf(char_type* s, streamsize n) {
+               this->setg(s, s, s + n);
+               return this;
+           }
+
+           pos_type seekpos(pos_type sp, ::std::ios_base::openmode which) {
+               if(which & ::std::ios_base::out)
+                  return pos_type(off_type(-1));
+               off_type size = static_cast<off_type>(this->egptr() - this->eback());
+               charT* g = this->eback();
+               if(off_type(sp) <= size)
+               {
+                  this->setg(g, g + off_type(sp), g + size);
+               }
+               return pos_type(off_type(-1));
+            }
+
+           pos_type seekoff(off_type off, ::std::ios_base::seekdir way, ::std::ios_base::openmode which) {
+               typedef typename boost::int_t<sizeof(way) * CHAR_BIT>::least cast_type;
+
+               if(which & ::std::ios_base::out)
+                  return pos_type(off_type(-1));
+               std::ptrdiff_t size = this->egptr() - this->eback();
+               std::ptrdiff_t pos = this->gptr() - this->eback();
+               charT* g = this->eback();
+               switch(static_cast<cast_type>(way))
+               {
+               case ::std::ios_base::beg:
+                  if((off < 0) || (off > size))
+                     return pos_type(off_type(-1));
+                  else
+                     this->setg(g, g + off, g + size);
+                  break;
+               case ::std::ios_base::end:
+                  if((off < 0) || (off > size))
+                     return pos_type(off_type(-1));
+                  else
+                     this->setg(g, g + size - off, g + size);
+                  break;
+               case ::std::ios_base::cur:
+               {
+                  std::ptrdiff_t newpos = static_cast<std::ptrdiff_t>(pos + off);
+                  if((newpos < 0) || (newpos > size))
+                     return pos_type(off_type(-1));
+                  else
+                     this->setg(g, g + newpos, g + size);
+                  break;
+               }
+               default: ;
+               }
+#ifdef BOOST_MSVC
+#pragma warning(push)
+#pragma warning(disable:4244)
+#endif
+               return static_cast<pos_type>(this->gptr() - this->eback());
+#ifdef BOOST_MSVC
+#pragma warning(pop)
+#endif
+            }
+        private:
+           parser_buf& operator=(const parser_buf&);
+           parser_buf(const parser_buf&);
         };
     }
 
@@ -1451,13 +1526,12 @@
 
 #if defined(BOOST_NO_STRINGSTREAM)
             typedef std::ostrstream                         out_stream_t;
-            typedef stl_buf_unlocker<std::strstreambuf, char>  unlocked_but_t;
 #elif defined(BOOST_NO_STD_LOCALE)
             typedef std::ostringstream                      out_stream_t;
-            typedef stl_buf_unlocker<std::stringbuf, char>  unlocked_but_t;
+            typedef parser_buf<std::streambuf, char>        buffer_t;
 #else
-            typedef std::basic_ostringstream<CharT, Traits>       out_stream_t;
-            typedef stl_buf_unlocker<std::basic_stringbuf<CharT, Traits>, CharT> unlocked_but_t;
+            typedef std::basic_ostringstream<CharT, Traits>                 out_stream_t;
+            typedef parser_buf<std::basic_streambuf<CharT, Traits>, CharT>  buffer_t;
 #endif
             typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_c<
                 RequiresStringbuffer,
@@ -1471,7 +1545,7 @@
             deduced_out_stream_t out_stream;
 
         public:
-            lexical_stream_limited_src(CharT* sta, CharT* fin)
+            lexical_stream_limited_src(CharT* sta, CharT* fin) BOOST_NOEXCEPT
               : start(sta)
               , finish(fin)
             {}
@@ -1540,8 +1614,9 @@
                 BOOST_STATIC_ASSERT((boost::is_same<char, CharT>::value));
 #endif
                 bool const result = !(out_stream << input).fail();
-                const unlocked_but_t* const p
-                        = static_cast<unlocked_but_t*>(out_stream.rdbuf()) ;
+                const buffer_t* const p = static_cast<buffer_t*>(
+                    static_cast<std::basic_streambuf<CharT, Traits>*>(out_stream.rdbuf())
+                );
                 start = p->pbase();
                 finish = p->pptr();
                 return result;
@@ -1893,35 +1968,34 @@
             template<typename InputStreamable>
             bool shr_using_base_class(InputStreamable& output)
             {
-#if (defined _MSC_VER)
-# pragma warning( push )
-  // conditional expression is constant
-# pragma warning( disable : 4127 )
-#endif
-                if(is_pointer<InputStreamable>::value)
-                    return false;
+                BOOST_STATIC_ASSERT_MSG(
+                    (!boost::is_pointer<InputStreamable>::value),
+                    "boost::lexical_cast can not convert to pointers"
+                );
 
 #if defined(BOOST_NO_STRINGSTREAM) || defined(BOOST_NO_STD_LOCALE)
-                // If you have compilation error at this point, than your STL library
-                // unsupports such conversions. Try updating it.
-                BOOST_STATIC_ASSERT((boost::is_same<char, CharT>::value));
+                BOOST_STATIC_ASSERT_MSG((boost::is_same<char, CharT>::value),
+                    "boost::lexical_cast can not convert, because your STL library does not "
+                    "support such conversions. Try updating it."
+                );
 #endif
 
 #if defined(BOOST_NO_STRINGSTREAM)
                 std::istrstream stream(start, finish - start);
-#elif defined(BOOST_NO_STD_LOCALE)
-                std::istringstream stream;
 #else
-                std::basic_istringstream<CharT, Traits> stream;
-#endif
-                static_cast<unlocked_but_t*>(stream.rdbuf())
-                        ->setg(start, start, finish);
+
+                buffer_t buf;
+                buf.setbuf(start, finish - start);
+#if defined(BOOST_NO_STD_LOCALE)
+                std::istream stream(&buf);
+#else
+                std::basic_istream<CharT, Traits> stream(&buf);
+#endif // BOOST_NO_STD_LOCALE
+#endif // BOOST_NO_STRINGSTREAM
 
                 stream.unsetf(std::ios::skipws);
                 lcast_set_precision(stream, static_cast<InputStreamable*>(0));
-#if (defined _MSC_VER)
-# pragma warning( pop )
-#endif
+
                 return stream >> output &&
                     stream.get() ==
 #if defined(__GNUC__) && (__GNUC__<3) && defined(BOOST_NO_STD_WSTRING)
Modified: branches/release/libs/conversion/doc/lexical_cast.qbk
==============================================================================
--- branches/release/libs/conversion/doc/lexical_cast.qbk	(original)
+++ branches/release/libs/conversion/doc/lexical_cast.qbk	2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
@@ -278,7 +278,9 @@
 
 * [*boost 1.54.0 :]
 
-    * Added code to convert boost::int128_type and boost::uint128_type (requires GCC 4.7 or higher).
+    * Added code to convert `boost::int128_type` and `boost::uint128_type` types (requires GCC 4.7 or higher).
+    * Conversions to pointers will now fail to compile, instead of throwing at runtime.
+    * Restored ability to get pointers to `lexical_cast` function (was broken in 1.53.0).
 
 * [*boost 1.53.0 :]
 
Modified: branches/release/libs/conversion/lexical_cast_test.cpp
==============================================================================
--- branches/release/libs/conversion/lexical_cast_test.cpp	(original)
+++ branches/release/libs/conversion/lexical_cast_test.cpp	2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
@@ -67,7 +67,6 @@
 void test_conversion_with_nonconst_char();
 void test_conversion_to_string();
 void test_conversion_from_to_wchar_t_alias();
-void test_conversion_to_pointer();
 void test_conversion_from_wchar_t();
 void test_conversion_to_wchar_t();
 void test_conversion_from_wstring();
@@ -100,7 +99,6 @@
     suite->add(BOOST_TEST_CASE(test_conversion_to_double));
     suite->add(BOOST_TEST_CASE(test_conversion_to_bool));
     suite->add(BOOST_TEST_CASE(test_conversion_from_to_wchar_t_alias));
-    suite->add(BOOST_TEST_CASE(test_conversion_to_pointer));
     suite->add(BOOST_TEST_CASE(test_conversion_to_string));
     suite->add(BOOST_TEST_CASE(test_conversion_with_nonconst_char));
 #ifndef BOOST_LCAST_NO_WCHAR_T
@@ -312,14 +310,6 @@
     BOOST_CHECK_EQUAL(std::string("123"), lexical_cast<std::string>(123ul));
 }
 
-void test_conversion_to_pointer()
-{
-    BOOST_CHECK_THROW(lexical_cast<char *>("Test"), bad_lexical_cast);
-#ifndef BOOST_LCAST_NO_WCHAR_T
-    BOOST_CHECK_THROW(lexical_cast<wchar_t *>("Test"), bad_lexical_cast);
-#endif
-}
-
 void test_conversion_from_wchar_t()
 {
 #ifndef BOOST_LCAST_NO_WCHAR_T
Modified: branches/release/libs/conversion/test/Jamfile.v2
==============================================================================
--- branches/release/libs/conversion/test/Jamfile.v2	(original)
+++ branches/release/libs/conversion/test/Jamfile.v2	2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
@@ -55,5 +55,7 @@
     [ run lexical_cast_integral_types_test.cpp ]
     [ run lexical_cast_stream_detection_test.cpp ]
     [ run lexical_cast_stream_traits_test.cpp ]
+    [ compile-fail lexical_cast_to_pointer_test.cpp ]
+    [ run lexical_cast_filesystem_test.cpp ../../filesystem/build//boost_filesystem/<link>static ]
   ;
 
Added: branches/release/libs/conversion/test/lexical_cast_filesystem_test.cpp
==============================================================================
--- (empty file)
+++ branches/release/libs/conversion/test/lexical_cast_filesystem_test.cpp	2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
@@ -0,0 +1,46 @@
+//  Unit test for boost::lexical_cast.
+//
+//  See http://www.boost.org for most recent version, including documentation.
+//
+//  Copyright Antony Polukhin, 2013.
+//
+//  Distributed under the Boost
+//  Software License, Version 1.0. (See accompanying file
+//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
+//
+// Test lexical_cast usage with long filesystem::path. Bug 7704.
+
+#include <boost/config.hpp>
+
+#include <boost/test/unit_test.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/filesystem/path.hpp>
+
+using namespace boost;
+
+void test_filesystem();
+
+unit_test::test_suite *init_unit_test_suite(int, char *[])
+{
+    unit_test::test_suite *suite =
+        BOOST_TEST_SUITE("lexical_cast unit test");
+    suite->add(BOOST_TEST_CASE(&test_filesystem));
+
+    return suite;
+}
+
+void test_filesystem()
+{
+    boost::filesystem::path p;
+    std::string s1 = "aaaaaaaaaaaaaaaaaaaaaaa";
+    p = boost::lexical_cast<boost::filesystem::path>(s1);
+    BOOST_CHECK(!p.empty());
+    BOOST_CHECK_EQUAL(p, s1);
+    p.clear();
+
+    const char ab[] = "aaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
+    p = boost::lexical_cast<boost::filesystem::path>(ab);
+    BOOST_CHECK(!p.empty());
+    BOOST_CHECK_EQUAL(p, ab);
+}
+
Added: branches/release/libs/conversion/test/lexical_cast_to_pointer_test.cpp
==============================================================================
--- (empty file)
+++ branches/release/libs/conversion/test/lexical_cast_to_pointer_test.cpp	2013-04-01 16:40:43 EDT (Mon, 01 Apr 2013)
@@ -0,0 +1,21 @@
+//  //  Unit test for boost::lexical_cast.
+//
+//  See http://www.boost.org for most recent version, including documentation.
+//
+//  Copyright Antony Polukhin, 2013.
+//
+//  Distributed under the Boost
+//  Software License, Version 1.0. (See accompanying file
+//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
+
+#include <boost/lexical_cast.hpp>
+#include <boost/type.hpp>
+
+#define BOOST_INCLUDE_MAIN
+#include <boost/test/test_tools.hpp>
+
+int test_main(int, char*[])
+{
+    boost::lexical_cast<char*>("Hello");
+    return 0;
+}