$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r63283 - in trunk: boost/filesystem/v3 libs/filesystem/v3/src libs/filesystem/v3/test
From: bdawes_at_[hidden]
Date: 2010-06-24 07:10:39
Author: bemandawes
Date: 2010-06-24 07:10:37 EDT (Thu, 24 Jun 2010)
New Revision: 63283
URL: http://svn.boost.org/trac/boost/changeset/63283
Log:
Provide const codecvt& arguments for all applicable class path functions
Text files modified: 
   trunk/boost/filesystem/v3/path.hpp               |   251 +++++++++++++++++++++++++-------------- 
   trunk/libs/filesystem/v3/src/path.cpp            |    13 -                                       
   trunk/libs/filesystem/v3/test/path_unit_test.cpp |    63 ++++++++++                              
   3 files changed, 223 insertions(+), 104 deletions(-)
Modified: trunk/boost/filesystem/v3/path.hpp
==============================================================================
--- trunk/boost/filesystem/v3/path.hpp	(original)
+++ trunk/boost/filesystem/v3/path.hpp	2010-06-24 07:10:37 EDT (Thu, 24 Jun 2010)
@@ -44,22 +44,6 @@
   //                                                                                    //
   //------------------------------------------------------------------------------------//
 
-/*
-   Why are there no const codecvt_type& arguments?
-   ------------------------------------------------
-
-   To hold down the size of the class path interface. Per function codecvt facets
-   just aren't needed very often in practice.
-
-   An RAII idiom can be used to ensure push/pop behavior as an alternative.
-
-   Note that codecvt() is passed to the path_traits::convert functions, since that
-   decouples the convert functions from class path.
-
-   const codecvt_type & can be added later, but once added, they can never be removed
-   since that would break user code.
-*/
-
   class BOOST_FILESYSTEM_DECL path
   {
   public:
@@ -68,12 +52,13 @@
     //  represent paths.
 
 #   ifdef BOOST_WINDOWS_API
-    typedef wchar_t                        value_type;
+    typedef wchar_t                                     value_type;
 #   else 
-    typedef char                           value_type;
+    typedef char                                        value_type;
 #   endif
-    typedef std::basic_string<value_type>  string_type;  
-    typedef path_traits::codecvt_type      codecvt_type;
+    typedef std::basic_string<value_type>               string_type;  
+    typedef std::codecvt<wchar_t, char, std::mbstate_t> codecvt_type;
+
 
     //  ----- character encoding conversions -----
 
@@ -101,20 +86,6 @@
     //
     //  See m_pathname comments for further important rationale.
 
-    //  Design alternative; each function can have an additional overload that
-    //  supplies a conversion locale. For example:
-    //
-    //      template< class ForwardIterator, class WStringConvert >
-    //      path(ForwardIterator begin, ForwardIterator end,
-    //            const std::locale & loc,
-    //            system::error_code & ec = boost::throws());
-    // 
-    //  This alternative was rejected as too complex for the limited benefits;
-    //  it nearly doubles the size of the interface, and adds a lot of
-    //  implementation and test code, yet would likely be rarely used. The same
-    //  effect can be achieved via the much simpler imbue() mechanism.
-
-
     //  TODO: rules needed for operating systems that use / or .
     //  differently, or format directory paths differently from file paths. 
     //
@@ -139,11 +110,28 @@
     //  multi-byte character strings which may have embedded nulls. Embedded null
     //  support is required for some Asian languages on Windows.
 
+    //  "const codecvt_type& cvt=codecvt()" default arguments are not used because some
+    //  compilers, such as Microsoft prior to VC++ 10, do not handle defaults correctly
+    //  in templates.
+
     //  -----  constructors  -----
 
     path(){}                                          
 
     path(const path& p) : m_pathname(p.m_pathname) {}
+ 
+    template <class Source>
+    path(Source const& source)
+    {
+      path_traits::dispatch(source, m_pathname, codecvt());
+    }
+
+    template <class Source>
+    path(Source const& source, const codecvt_type& cvt)
+    //  see note above explaining why codecvt() default arguments are not used
+    {
+      path_traits::dispatch(source, m_pathname, cvt);
+    }
 
     template <class InputIterator>
     path(InputIterator begin, InputIterator end)
@@ -156,10 +144,15 @@
       }
     }
 
-    template <class Source>
-    path(Source const& source)
-    {
-      path_traits::dispatch(source, m_pathname, codecvt());
+    template <class InputIterator>
+    path(InputIterator begin, InputIterator end, const codecvt_type& cvt)
+    { 
+      if (begin != end)
+      {
+        std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
+          s(begin, end);
+        path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
+      }
     }
 
     //  -----  assignments  -----
@@ -170,27 +163,41 @@
       return *this;
     }
 
+    template <class Source>
+    path& operator=(Source const& source)
+    {
+      m_pathname.clear();
+      path_traits::dispatch(source, m_pathname, codecvt());
+      return *this;
+    }
+
+    template <class Source>
+    path& assign(Source const& source, const codecvt_type& cvt)
+    {
+      m_pathname.clear();
+      path_traits::dispatch(source, m_pathname, cvt);
+      return *this;
+    }
+
     template <class InputIterator>
     path& assign(InputIterator begin, InputIterator end)
+    {
+      return assign(begin, end, codecvt());
+    }
+
+    template <class InputIterator>
+    path& assign(InputIterator begin, InputIterator end, const codecvt_type& cvt)
     { 
       m_pathname.clear();
       if (begin != end)
       {
         std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
           s(begin, end);
-        path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, codecvt());
+        path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
       }
       return *this;
     }
 
-    template <class Source>
-    path& operator=(Source const& source)
-    {
-      m_pathname.clear();
-      path_traits::dispatch(source, m_pathname, codecvt());
-      return *this;
-    }
-
     //  -----  appends  -----
 
     //  if a separator is added, it is the preferred separator for the platform;
@@ -198,22 +205,34 @@
 
     path& operator/=(const path& p);
 
-    template <class InputIterator>
-    path& append(InputIterator begin, InputIterator end);
+    template <class Source>
+    path& operator/=(Source const& source)
+    {
+      return append(source, codecvt());
+    }
 
     template <class Source>
-    path& operator/=(Source const& source);
+    path& append(Source const& source, const codecvt_type& cvt);
+
+    template <class InputIterator>
+    path& append(InputIterator begin, InputIterator end)
+    { 
+      return append(begin, end, codecvt());
+    }
+
+    template <class InputIterator>
+    path& append(InputIterator begin, InputIterator end, const codecvt_type& cvt);
 
     //  -----  modifiers  -----
 
     void   clear()             { m_pathname.clear(); }
     path&  make_absolute(const path& base); 
     path&  make_preferred()
-#                              ifdef BOOST_POSIX_API
-                               { return *this; }  // POSIX no effect
-#                              else // BOOST_WINDOWS_API
-                               ;  // change slashes to backslashes
-#                              endif
+#   ifdef BOOST_POSIX_API
+      { return *this; }  // POSIX no effect
+#   else // BOOST_WINDOWS_API
+      ;  // change slashes to backslashes
+#   endif
     path&  remove_filename();
     path&  replace_extension(const path& new_extension = path());
     void   swap(path& rhs)     { m_pathname.swap(rhs.m_pathname); }
@@ -245,18 +264,36 @@
     template <class String>
     String string() const;
 
+    template <class String>
+    String string(const codecvt_type& cvt) const;
+
 #   ifdef BOOST_WINDOWS_API
-    const std::string    string() const;
+    const std::string string() const { return string(codecvt()); } 
+    const std::string string(const codecvt_type& cvt) const
+    { 
+      std::string tmp;
+      if (!m_pathname.empty())
+        path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
+          tmp, cvt);
+      return tmp;
+    }
+    
+    //  string_type is std::wstring, so there is no conversion
     const std::wstring&  wstring() const { return m_pathname; }
+    const std::wstring&  wstring(const codecvt_type&) const { return m_pathname; }
 
 #   else   // BOOST_POSIX_API
-    const std::string&  string() const   { return m_pathname; }
-    const std::wstring  wstring() const
+    //  string_type is std::string, so there is no conversion
+    const std::string&  string() const { return m_pathname; }
+    const std::string&  string(const codecvt_type&) const { return m_pathname; }
+
+    const std::wstring  wstring() const { return wstring(codecvt()); }
+    const std::wstring  wstring(const codecvt_type& cvt) const
     { 
       std::wstring tmp;
       if (!m_pathname.empty())
         path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
-          tmp, codecvt());
+          tmp, cvt);
       return tmp;
     }
 
@@ -267,13 +304,21 @@
     template <class String>
     String generic_string() const;
 
+    template <class String>
+    String generic_string(const codecvt_type& cvt) const;
+
 #   ifdef BOOST_WINDOWS_API
-    const std::string   generic_string() const; 
+    const std::string   generic_string() const { return generic_string(codecvt()); } 
+    const std::string   generic_string(const codecvt_type& cvt) const; 
     const std::wstring  generic_wstring() const;
+    const std::wstring  generic_wstring(const codecvt_type&) const { return generic_wstring(); };
 
 #   else // BOOST_POSIX_API
+    //  On POSIX-like systems, the generic format is the same as the native format
     const std::string&  generic_string() const  { return m_pathname; }
+    const std::string&  generic_string(const codecvt_type&) const  { return m_pathname; }
     const std::wstring  generic_wstring() const { return wstring(); }
+    const std::wstring  generic_wstring(const codecvt_type&) const { return wstring(); }
 
 #   endif
 
@@ -312,11 +357,11 @@
 
     //  -----  imbue  -----
 
-    static std::locale imbue(const std::locale & loc);
+    static std::locale imbue(const std::locale& loc);
 
     //  -----  codecvt  -----
 
-    static const codecvt_type & codecvt()
+    static const codecvt_type& codecvt()
     {
       return *wchar_t_codecvt_facet();
     }
@@ -453,30 +498,30 @@
                                          // m_pos == m_path_ptr->m_pathname.size()
   }; // path::iterator
 
-  //------------------------------------------------------------------------------------//
-  //                                                                                    //
-  //                            class scoped_path_locale                                //
-  //                                                                                    //
-  //------------------------------------------------------------------------------------//
+  ////------------------------------------------------------------------------------------//
+  ////                                                                                    //
+  ////                            class scoped_path_locale                                //
+  ////                                                                                    //
+  ////------------------------------------------------------------------------------------//
  
-  class scoped_path_locale
-  {
-  public:
-    scoped_path_locale(const std::locale & loc)
-                      : m_saved_locale(loc)
-    {
-      path::imbue(loc);
-    }
-
-    ~scoped_path_locale()   // never throws()
-    {
-      try { path::imbue(m_saved_locale); }
-      catch (...) {}
-    };
-
-  private:
-    std::locale m_saved_locale;
-  };
+  //class scoped_path_locale
+  //{
+  //public:
+  //  scoped_path_locale(const std::locale & loc)
+  //                    : m_saved_locale(loc)
+  //  {
+  //    path::imbue(loc);
+  //  }
+
+  //  ~scoped_path_locale()   // never throws()
+  //  {
+  //    try { path::imbue(m_saved_locale); }
+  //    catch (...) {}
+  //  };
+
+  //private:
+  //  std::locale m_saved_locale;
+  //};
    
   //------------------------------------------------------------------------------------//
   //                                                                                    //
@@ -581,26 +626,26 @@
 //--------------------------------------------------------------------------------------//
 
   template <class InputIterator>
-  path& path::append(InputIterator begin, InputIterator end)
+  path& path::append(InputIterator begin, InputIterator end, const codecvt_type& cvt)
   { 
     if (begin == end)
       return *this;
     string_type::size_type sep_pos(m_append_separator_if_needed());
     std::basic_string<typename std::iterator_traits<InputIterator>::value_type>
       s(begin, end);
-    path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, codecvt());
+    path_traits::convert(s.c_str(), s.c_str()+s.size(), m_pathname, cvt);
     if (sep_pos)
       m_erase_redundant_separator(sep_pos);
     return *this;
   }
 
   template <class Source>
-  path& path::operator/=(Source const & source)
+  path& path::append(Source const & source, const codecvt_type& cvt)
   {
     if (path_traits::empty(source))
       return *this;
     string_type::size_type sep_pos(m_append_separator_if_needed());
-    path_traits::dispatch(source, m_pathname, codecvt());
+    path_traits::dispatch(source, m_pathname, cvt);
     if (sep_pos)
       m_erase_redundant_separator(sep_pos);
     return *this;
@@ -611,16 +656,36 @@
 //--------------------------------------------------------------------------------------//
 
   template <> inline
-  std::string path::string<std::string>() const    { return string(); }
+  std::string path::string<std::string>() const
+    { return string(); }
+
+  template <> inline
+  std::wstring path::string<std::wstring>() const
+    { return wstring(); }
+
+  template <> inline
+  std::string path::string<std::string>(const codecvt_type& cvt) const
+    { return string(cvt); }
+
+  template <> inline
+  std::wstring path::string<std::wstring>(const codecvt_type& cvt) const
+    { return wstring(cvt); }
+
+  template <> inline
+  std::string path::generic_string<std::string>() const
+    { return generic_string(); }
 
   template <> inline
-  std::wstring path::string<std::wstring>() const  { return wstring(); }
+  std::string path::generic_string<std::string>(const codecvt_type& cvt) const
+    { return generic_string(cvt); }
 
   template <> inline
-  std::string path::generic_string<std::string>() const   { return generic_string(); }
+  std::wstring path::generic_string<std::wstring>() const
+    { return generic_wstring(); }
 
   template <> inline
-  std::wstring path::generic_string<std::wstring>() const { return generic_wstring(); }
+  std::wstring path::generic_string<std::wstring>(const codecvt_type& cvt) const
+    { return generic_wstring(cvt); }
 
 
 }  // namespace filesystem3
Modified: trunk/libs/filesystem/v3/src/path.cpp
==============================================================================
--- trunk/libs/filesystem/v3/src/path.cpp	(original)
+++ trunk/libs/filesystem/v3/src/path.cpp	2010-06-24 07:10:37 EDT (Thu, 24 Jun 2010)
@@ -148,15 +148,6 @@
 
 # ifdef BOOST_WINDOWS_API
 
-  const std::string  path::string() const
-  { 
-    std::string tmp;
-    if (!m_pathname.empty())
-      path_traits::convert(&*m_pathname.begin(), &*m_pathname.begin()+m_pathname.size(),
-        tmp, codecvt());
-    return tmp;
-  }
-
   void path::m_portable()
   {
     for (string_type::iterator it = m_pathname.begin();
@@ -167,11 +158,11 @@
     }
   }
 
-  const std::string path::generic_string() const
+  const std::string path::generic_string(const codecvt_type& cvt) const
   { 
     path tmp(*this);
     tmp.m_portable();
-    return tmp.string();
+    return tmp.string(cvt);
   }
 
   const std::wstring path::generic_wstring() const
Modified: trunk/libs/filesystem/v3/test/path_unit_test.cpp
==============================================================================
--- trunk/libs/filesystem/v3/test/path_unit_test.cpp	(original)
+++ trunk/libs/filesystem/v3/test/path_unit_test.cpp	2010-06-24 07:10:37 EDT (Thu, 24 Jun 2010)
@@ -175,6 +175,9 @@
     path xll(wl);                                      // std::list<wchar_t>
     PATH_IS(xll, L"wstring");
     BOOST_TEST_EQ(xll.native().size(), 7U);
+
+    // easy-to-make coding errors
+    // path e1(x0, path::codecvt());  // fails to compile, and that is OK
   }
 
   path x;
@@ -636,6 +639,65 @@
     std::cout << "  locale testing complete" << std::endl;
   }
 
+  //  test_codecvt_argument  -----------------------------------------------------------//
+
+  void test_codecvt_argument()
+  {
+    std::cout << "testing codecvt arguments..." << std::endl;
+
+    //  U+2780 is DINGBAT CIRCLED SANS-SERIF DIGIT ONE == 0xE2 0x9E 0x80 in UTF-8
+    //  U+1234 is ETHIOPIC SYLLABLE SEE == 0xE1 0x88 0xB4 in UTF-8
+
+    const char * c1 = "\xE2\x9E\x80\xE1\x88\xB4";
+    const std::string s1("\xE2\x9E\x80\xE1\x88\xB4");
+    const std::wstring ws1(L"\u2780\u1234");
+
+    fs::detail::utf8_codecvt_facet cvt;
+
+    //  constructors
+    path p(c1, cvt);
+    CHECK(p == path(ws1));
+    path p1(s1.begin(), s1.end(), cvt);
+    CHECK(p1 == path(ws1));
+    // path p2(p1, cvt);  // fails to compile, and that is OK
+
+    //  assigns
+    p1.clear();
+    p1.assign(s1,cvt);
+    CHECK(p == p1);
+    p1.clear();
+    p1.assign(s1.begin(), s1.end(), cvt);
+    CHECK(p == p1);
+    // p1.assign(p, cvt);  // fails to compile, and that is OK
+
+
+    //  appends
+    p1.clear();
+    p1.append(s1,cvt);
+    CHECK(p == p1);
+    p1.clear();
+    p1.append(s1.begin(), s1.end(), cvt);
+    CHECK(p == p1);
+    // p1.append(p, cvt);  // fails to compile, and that is OK
+
+    //  native observers
+#   ifdef BOOST_WINDOWS_API
+    CHECK(p.string<std::string>() != s1); // non-Windows systems may have UTF-8 as default
+#   endif
+    CHECK(p.string<std::string>(cvt) == s1);
+    CHECK(p.string(cvt) == s1);
+    CHECK(p.string<std::wstring>(cvt) == ws1);
+    CHECK(p.wstring(cvt) == ws1);
+
+    //  generic observers
+    CHECK(p.generic_string<std::string>(cvt) == s1);
+    CHECK(p.generic_string(cvt) == s1);
+    CHECK(p.generic_string<std::wstring>(cvt) == ws1);
+    CHECK(p.generic_wstring(cvt) == ws1);
+
+    std::cout << "  codecvt arguments testing complete" << std::endl;
+  }
+
   //  test_overloads  ------------------------------------------------------------------//
 
   void test_overloads()
@@ -904,6 +966,7 @@
   test_decompositions();
   test_queries();
   test_imbue_locale();
+  test_codecvt_argument();
   test_error_handling();
 
 # if 0