Boost logo

Boost-Commit :

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


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk