Bläddra i källkod

reimplemented io support for basic types

jan p springer 12 år sedan
förälder
incheckning
623cdaa552
3 ändrade filer med 420 tillägg och 200 borttagningar
  1. 84 34
      glm/gtx/io.hpp
  2. 295 155
      glm/gtx/io.inl
  3. 41 11
      test/gtx/gtx_io.cpp

+ 84 - 34
glm/gtx/io.hpp

@@ -33,6 +33,10 @@
 /// 
 /// @brief std::[w]ostream support for glm types
 ///
+///        std::[w]ostream support for glm types + precision/width/etc. manipulators
+///        based on howard hinnant's std::chrono io proposal
+///        [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html]
+///
 /// <glm/gtx/io.hpp> needs to be included to use these functionalities.
 ///////////////////////////////////////////////////////////////////////////////////
 
@@ -47,8 +51,11 @@
 #	pragma message("GLM: GLM_GTX_io extension included")
 #endif
 
-#include <iosfwd>  // std::basic_ostream<> (fwd)
-#include <utility> // std::pair<>
+#include <boost/io_fwd.hpp>      // basic_ios_all_saver<> (fwd)
+#include <boost/noncopyable.hpp> // boost::noncopyable
+#include <iosfwd>                // std::basic_ostream<> (fwd)
+#include <locale>                // std::locale, std::locale::facet, std::locale::id
+#include <utility>               // std::pair<>
 
 namespace glm
 {
@@ -58,60 +65,103 @@ namespace glm
   namespace io
   {
     
-    class precision_guard {
+    enum class order_type { column_major, row_major, };
+    
+    template <typename CTy>
+    class format_punct : public std::locale::facet {
 
-    public:
+      typedef CTy char_type;
       
-      GLM_FUNC_DECL explicit precision_guard();
-      GLM_FUNC_DECL         ~precision_guard();
-                
-    private:
+    public:
 
-      unsigned precision_;
-      unsigned value_width_;
+      static std::locale::id id;
+
+      bool       formatted;
+      unsigned   precision;
+      unsigned   width;
+      char_type  separator;
+      char_type  delim_left;
+      char_type  delim_right;
+      char_type  space;
+      char_type  newline;
+      order_type order;
+      
+      explicit format_punct(size_t a = 0);
+      explicit format_punct(format_punct const&);
       
     };
 
-    enum class order_t { column_major, row_major, };
-
-    class format_guard {
+    template <typename CTy, typename CTr = std::char_traits<CTy> >
+    class basic_format_saver : private boost::noncopyable {
 
     public:
 
-      GLM_FUNC_DECL explicit format_guard();
-      GLM_FUNC_DECL         ~format_guard();
-                
+      explicit basic_format_saver(std::basic_ios<CTy,CTr>&);
+              ~basic_format_saver();
+
     private:
 
-      order_t order_;
-      char    cr_;
+      boost::io::basic_ios_all_saver<CTy> const ias_;
       
     };
 
-    // decimal places (dflt: 3)
-    GLM_FUNC_DECL unsigned& precision();
+    typedef basic_format_saver<char>     format_saver;
+    typedef basic_format_saver<wchar_t> wformat_saver;
+    
+    struct formatted   { /* empty */ };
+    struct unformatted { /* empty */ };
+    
+    struct precision {
 
-    // sign + value + '.' + decimals (dflt: 1 + 4 + 1 + precision())
-    GLM_FUNC_DECL unsigned& value_width();
+      unsigned value;
+      
+      explicit precision(unsigned);
+      
+    };
 
-    // matrix output order (dflt: row_major)
-    GLM_FUNC_DECL order_t& order();
+    struct width {
 
-    // carriage/return char (dflt: '\n')
-    GLM_FUNC_DECL char& cr();
+      unsigned value;
+      
+      explicit width(unsigned);
+      
+    };
 
-    // matrix output order -> column_major
-    GLM_FUNC_DECL std::ios_base& column_major(std::ios_base&);
+    template <typename CTy>
+    struct delimeter {
 
-    // matrix output order -> row_major
-    GLM_FUNC_DECL std::ios_base& row_major   (std::ios_base&);
+      CTy value[3];
+      
+      explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ',');
+      
+    };
 
-    // carriage/return char -> '\n'
-    GLM_FUNC_DECL std::ios_base& formatted   (std::ios_base&);
+    struct order {
 
-    // carriage/return char -> ' '
-    GLM_FUNC_DECL std::ios_base& unformatted (std::ios_base&);
+      order_type value;
+      
+      explicit order(order_type);
+      
+    };
+    
+    // functions, inlined (inline)
 
+    template <typename FTy, typename CTy, typename CTr>
+    FTy const& get_facet(std::basic_ios<CTy,CTr>&);
+    
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, formatted const&);
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, unformatted const&);
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, precision const&);
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, width const&);
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, delimeter<CTy> const&);
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, order const&);
+    
   }//namespace io
 
   namespace detail

+ 295 - 155
glm/gtx/io.inl

@@ -2,12 +2,12 @@
 // OpenGL Mathematics Copyright (c) 2005 - 2013 G-Truc Creation (www.g-truc.net)
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 // Created : 2013-11-22
-// Updated : 2013-11-22
+// Updated : 2013-12-17
 // Licence : This source is under MIT License
 // File    : glm/gtx/inl.inl
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
-// #include <boost/io/ios_state.hpp> // boost::io::ios_all_saver
+#include <boost/io/ios_state.hpp> // boost::io::ios_all_saver
 #include <iomanip>                // std::setfill<>, std::fixed, std::setprecision, std::right,
                                   // std::setw
 #include <ostream>                // std::basic_ostream<>
@@ -17,91 +17,143 @@ namespace glm
   namespace io
   {
   
+    template <typename CTy>
     /* explicit */ GLM_FUNC_QUALIFIER
-    precision_guard::precision_guard()
-      : precision_  (precision()),
-        value_width_(value_width())
+    format_punct<CTy>::format_punct(size_t a)
+      : std::locale::facet(a),
+        formatted         (true),
+        precision         (3),
+        width             (1 + 4 + 1 + precision),
+        separator         (','),
+        delim_left        ('['),
+        delim_right       (']'),
+        space             (' '),
+        newline           ('\n'),
+        order             (order_type::row_major)
     {}
 
-    GLM_FUNC_QUALIFIER
-    precision_guard::~precision_guard()
+    template <typename CTy>
+    /* explicit */ GLM_FUNC_QUALIFIER
+    format_punct<CTy>::format_punct(format_punct const& a)
+      : std::locale::facet(0),
+        formatted         (a.formatted),
+        precision         (a.precision),
+        width             (a.width),
+        separator         (a.separator),
+        delim_left        (a.delim_left),
+        delim_right       (a.delim_right),
+        space             (a.space),
+        newline           (a.newline),
+        order             (a.order)
+    {}
+    
+    template <typename CTy> std::locale::id format_punct<CTy>::id;
+
+    template <typename CTy, typename CTr>
+    /* explicit */ GLM_FUNC_QUALIFIER
+    basic_format_saver<CTy,CTr>::basic_format_saver(std::basic_ios<CTy,CTr>& a)
+      : boost::noncopyable(),
+        ias_              (a)
     {
-      value_width() = value_width_;
-      precision()   = precision_;
+      a.imbue(std::locale(a.getloc(), new format_punct<CTy>(get_facet<format_punct<CTy>>(a))));
     }
 
+    template <typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER
+    basic_format_saver<CTy,CTr>::~basic_format_saver()
+    {}
+    
+    /* explicit */ GLM_FUNC_QUALIFIER
+    precision::precision(unsigned a)
+      : value(a)
+    {}
+
     /* explicit */ GLM_FUNC_QUALIFIER
-    format_guard::format_guard()
-      : order_(order()),
-        cr_   (cr())
+    width::width(unsigned a)
+      : value(a)
     {}
 
-    GLM_FUNC_QUALIFIER
-    format_guard::~format_guard()
+    template <typename CTy>
+    /* explicit */ GLM_FUNC_QUALIFIER
+    delimeter<CTy>::delimeter(CTy a, CTy b, CTy c)
+      : value()
     {
-      cr()    = cr_;
-      order() = order_;
+      value[0] = a;
+      value[1] = b;
+      value[2] = c;
     }
 
-    GLM_FUNC_QUALIFIER unsigned&
-    precision()
-    {
-      static unsigned p(3);
-
-      return p;
-    }
+    /* explicit */ GLM_FUNC_QUALIFIER
+    order::order(order_type a)
+      : value(a)
+    {}
     
-    GLM_FUNC_QUALIFIER unsigned&
-    value_width()
+    template <typename FTy, typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER FTy const&
+    get_facet(std::basic_ios<CTy,CTr>& ios)
     {
-      static unsigned p(9);
+      if (!std::has_facet<FTy>(ios.getloc())) {
+        ios.imbue(std::locale(ios.getloc(), new FTy));
+      }
 
-      return p;
+      return std::use_facet<FTy>(ios.getloc());
     }
-    
-    GLM_FUNC_QUALIFIER order_t&
-    order()
+
+    template <typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&
+    operator<<(std::basic_ostream<CTy, CTr>& os, formatted const&)
     {
-      static order_t p(order_t::row_major);
+      const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy>>(os)).formatted = true;
 
-      return p;
+      return os;
     }
-    
-    GLM_FUNC_QUALIFIER char&
-    cr()
+
+    template <typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&
+    operator<<(std::basic_ostream<CTy, CTr>& os, unformatted const&)
     {
-      static char p('\n'); return p;
+      const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy>>(os)).formatted = false;
+
+      return os;
     }
     
-    GLM_FUNC_QUALIFIER std::ios_base&
-    column_major(std::ios_base& os)
+    template <typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&
+    operator<<(std::basic_ostream<CTy, CTr>& os, precision const& a)
     {
-      order() = order_t::column_major;
-      
+      const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy>>(os)).precision = a.value;
+
       return os;
     }
-    
-    GLM_FUNC_QUALIFIER std::ios_base&
-    row_major(std::ios_base& os)
+
+    template <typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&
+    operator<<(std::basic_ostream<CTy, CTr>& os, width const& a)
     {
-      order() = order_t::row_major;
-      
+      const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy>>(os)).width = a.value;
+
       return os;
     }
 
-    GLM_FUNC_QUALIFIER std::ios_base&
-    formatted(std::ios_base& os)
+    template <typename CTy, typename CTr>
+    std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os,
+                                             delimeter<CTy> const& a)
     {
-      cr() = '\n';
+      format_punct<CTy>& fmt(const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy>>(os)));
+
+      fmt.delim_left  = a.value[0];
+      fmt.delim_right = a.value[1];
+      fmt.separator   = a.value[2];
       
       return os;
     }
-    
-    GLM_FUNC_QUALIFIER std::ios_base&
-    unformatted(std::ios_base& os)
+
+    template <typename CTy, typename CTr>
+    GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&
+    operator<<(std::basic_ostream<CTy, CTr>& os, order const& a)
     {
-      cr() = ' ';
-      
+      const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy>>(os)).order = a.value;
+
       return os;
     }
     
@@ -109,8 +161,6 @@ namespace glm
   
   namespace detail {
     
-    // functions, inlined (inline)
-
     template <typename CTy, typename CTr, typename T, precision P>
     GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>&
     operator<<(std::basic_ostream<CTy,CTr>& os, tquat<T,P> const& a)
@@ -118,17 +168,26 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        // boost::io::ios_all_saver const ias(os);
-      
-        os << std::fixed << std::setprecision(io::precision())
-           << '['
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.w << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.x << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.y << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.z
-           << ']';
-      }
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
 
+        if (fmt.formatted) {
+          boost::io::basic_ios_all_saver<CTy> const ias(os);
+        
+          os << std::fixed
+             << std::right
+             << std::setprecision(fmt.precision)
+             << std::setfill(fmt.space)
+             << fmt.delim_left
+             << std::setw(fmt.width) << a.w << fmt.separator
+             << std::setw(fmt.width) << a.x << fmt.separator
+             << std::setw(fmt.width) << a.y << fmt.separator
+             << std::setw(fmt.width) << a.z
+             << fmt.delim_right;
+        } else {
+          os << a.w << fmt.space << a.x << fmt.space << a.y << fmt.space << a.z;
+        }
+      }
+      
       return os;
     }
     
@@ -139,13 +198,22 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        // boost::io::ios_all_saver const ias(os);
-      
-        os << std::fixed << std::setprecision(io::precision())
-           << '['
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.x << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.y
-           << ']';
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+
+        if (fmt.formatted) {
+          boost::io::basic_ios_all_saver<CTy> const ias(os);
+          
+          os << std::fixed
+             << std::right
+             << std::setprecision(fmt.precision)
+             << std::setfill(fmt.space)
+             << fmt.delim_left
+             << std::setw(fmt.width) << a.x << fmt.separator
+             << std::setw(fmt.width) << a.y
+             << fmt.delim_right;
+        } else {
+          os << a.x << fmt.space << a.y;
+        }
       }
 
       return os;
@@ -158,19 +226,28 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        // boost::io::ios_all_saver const ias(os);
-      
-        os << std::fixed << std::setprecision(io::precision())
-           << '['
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.x << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.y << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.z
-           << ']';
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+
+        if (fmt.formatted) {
+          boost::io::basic_ios_all_saver<CTy> const ias(os);
+          
+          os << std::fixed
+             << std::right
+             << std::setprecision(fmt.precision)
+             << std::setfill(fmt.space)
+             << fmt.delim_left
+             << std::setw(fmt.width) << a.x << fmt.separator
+             << std::setw(fmt.width) << a.y << fmt.separator
+             << std::setw(fmt.width) << a.z
+             << fmt.delim_right;
+        } else {
+          os << a.x << fmt.space << a.y << fmt.space << a.z;
+        }
       }
-
+      
       return os;
     }
-
+    
     template <typename CTy, typename CTr, typename T, precision P>
     GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>&
     operator<<(std::basic_ostream<CTy,CTr>& os, tvec4<T,P> const& a)
@@ -178,17 +255,26 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        // boost::io::ios_all_saver const ias(os);
-      
-        os << std::fixed << std::setprecision(io::precision())
-           << '['
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.x << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.y << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.z << ','
-           << std::right << std::setfill<CTy>(' ') << std::setw(io::value_width()) << a.w
-           << ']';
-      }
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
 
+        if (fmt.formatted) {
+          boost::io::basic_ios_all_saver<CTy> const ias(os);
+        
+          os << std::fixed
+             << std::right
+             << std::setprecision(fmt.precision)
+             << std::setfill(fmt.space)
+             << fmt.delim_left
+             << std::setw(fmt.width) << a.x << fmt.separator
+             << std::setw(fmt.width) << a.y << fmt.separator
+             << std::setw(fmt.width) << a.z << fmt.separator
+             << std::setw(fmt.width) << a.w
+             << fmt.delim_right;
+        } else {
+          os << a.x << fmt.space << a.y << fmt.space << a.z << fmt.space << a.w;
+        }
+      }
+      
       return os;
     }
 
@@ -199,15 +285,20 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat2x2<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat2x2<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
-        
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << ']';
+
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1];
+        }
       }
 
       return os;
@@ -220,16 +311,21 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat3x2<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat3x2<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << io::cr()
-           << ' ' << m[2] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.newline
+             << fmt.space      << m[2] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1] << fmt.space << m[2];
+        }
       }
 
       return os;
@@ -242,17 +338,22 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat4x2<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat4x2<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << io::cr()
-           << ' ' << m[2] << io::cr()
-           << ' ' << m[3] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.newline
+             << fmt.space      << m[2] << fmt.newline
+             << fmt.space      << m[3] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1] << fmt.space << m[2] << fmt.space << m[3];
+        }
       }
 
       return os;
@@ -265,15 +366,20 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat2x3<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat2x3<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1];
+        }
       }
 
       return os;
@@ -286,16 +392,21 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat3x3<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat3x3<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << io::cr()
-           << ' ' << m[2] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.newline
+             << fmt.space      << m[2] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1] << fmt.space << m[2];
+        }
       }
 
       return os;
@@ -308,17 +419,22 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat4x3<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat4x3<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << io::cr()
-           << ' ' << m[2] << io::cr()
-           << ' ' << m[3] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.newline
+             << fmt.space      << m[2] << fmt.newline
+             << fmt.space      << m[3] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1] << fmt.space << m[2] << fmt.space << m[3];
+        }
       }
 
       return os;
@@ -331,15 +447,20 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat2x4<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat2x4<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1];
+        }
       }
 
       return os;
@@ -352,16 +473,21 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat3x4<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat3x4<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << io::cr()
-           << ' ' << m[2] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.newline
+             << fmt.space      << m[2] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1] << fmt.space << m[2];
+        }
       }
 
       return os;
@@ -374,17 +500,22 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat4x4<T,P> m(a);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat4x4<T,P>                 m(a);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           m = transpose(a);
         }
 
-        os << io::cr()
-           << '[' << m[0] << io::cr()
-           << ' ' << m[1] << io::cr()
-           << ' ' << m[2] << io::cr()
-           << ' ' << m[3] << ']';
+        if (fmt.formatted) {
+          os << fmt.newline
+             << fmt.delim_left << m[0] << fmt.newline
+             << fmt.space      << m[1] << fmt.newline
+             << fmt.space      << m[2] << fmt.newline
+             << fmt.space      << m[3] << fmt.delim_right;
+        } else {
+          os << m[0] << fmt.space << m[1] << fmt.space << m[2] << fmt.space << m[3];
+        }
       }
 
       return os;
@@ -398,19 +529,28 @@ namespace glm
       typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
 
       if (cerberus) {
-        tmat4x4<T,P> ml(a.first);
-        tmat4x4<T,P> mr(a.second);
+        io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy>>(os));
+        tmat4x4<T,P>                 ml(a.first);
+        tmat4x4<T,P>                 mr(a.second);
 
-        if (io::order_t::row_major == io::order()) {
+        if (io::order_type::row_major == fmt.order) {
           ml = transpose(a.first);
           mr = transpose(a.second);
         }
+
+        if (fmt.formatted) {
+          CTy const& l(fmt.delim_left);
+          CTy const& r(fmt.delim_right);
+          CTy const& s(fmt.space);
         
-        os << io::cr()
-           << '[' << ml[0] << "  [" << mr[0] << io::cr()
-           << ' ' << ml[1] << "   " << mr[1] << io::cr()
-           << ' ' << ml[2] << "   " << mr[2] << io::cr()
-           << ' ' << ml[3] << "]  " << mr[3] << ']';
+          os << fmt.newline
+             << l << ml[0] << s << s << l << mr[0] << fmt.newline
+             << s << ml[1] << s << s << s << mr[1] << fmt.newline
+             << s << ml[2] << s << s << s << mr[2] << fmt.newline
+             << s << ml[3] << r << s << s << mr[3] << r;
+        } else {
+          os << ml << fmt.space << mr;
+        }
       }
 
       return os;

+ 41 - 11
test/gtx/gtx_io.cpp

@@ -34,6 +34,32 @@ namespace {
 
 } // namespace {
 
+template <typename T, glm::precision P, typename OS>
+int test_io_quat(OS& os)
+{
+  os << '\n'
+     << typeid(OS).name()
+     << '\n';
+  
+  glm::detail::tquat<T,P> const q(1, 0, 0, 0);
+
+  {
+    glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
+    
+    os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2)
+       << "quat<" << typeid(T).name() << ',' << P << ">: " << q << '\n';
+  }
+  
+  {
+    glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
+  
+    os << glm::io::unformatted()
+       << "quat<" << typeid(T).name() << ',' << P << ">: " << q << '\n';
+  }  
+
+  return 0;
+}
+
 template <typename T, glm::precision P, typename OS>
 int test_io_vec(OS& os)
 {
@@ -49,12 +75,10 @@ int test_io_vec(OS& os)
      << "vec3<" << typeid(T).name() << ',' << P << ">: " << v3 << '\n'
      << "vec4<" << typeid(T).name() << ',' << P << ">: " << v4 << '\n';
 
-  glm::io::precision_guard const iopg;
-  
-  glm::io::precision()   = 2;
-  glm::io::value_width() = 1 + 2 + 1 + glm::io::precision();
+  glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
   
-  os << "vec2<" << typeid(T).name() << ',' << P << ">: " << v2 << '\n'
+  os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2)
+     << "vec2<" << typeid(T).name() << ',' << P << ">: " << v2 << '\n'
      << "vec3<" << typeid(T).name() << ',' << P << ">: " << v3 << '\n'
      << "vec4<" << typeid(T).name() << ',' << P << ">: " << v4 << '\n';
 
@@ -93,12 +117,10 @@ int test_io_mat(OS& os)
      << "mat4x4<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat4x4<T,P>(v4_1, v4_2, v4_3, v4_4) << '\n';
 #endif
   
-  glm::io::precision_guard const iopg;
-  
-  glm::io::precision()   = 2;
-  glm::io::value_width() = 1 + 2 + 1 + glm::io::precision();
+  glm::io::basic_format_saver<typename OS::char_type> const iofs(os);
   
-  os << "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x2<T,P>(v2_1, v2_2) << '\n'
+  os << glm::io::precision(2) << glm::io::width(1 + 2 + 1 + 2)
+     << "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x2<T,P>(v2_1, v2_2) << '\n'
      << "mat2x3<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x3<T,P>(v3_1, v3_2) << '\n'
      << "mat2x4<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x4<T,P>(v4_1, v4_2) << '\n'
      << "mat3x2<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat3x2<T,P>(v2_1, v2_2, v2_3) << '\n'
@@ -108,7 +130,8 @@ int test_io_mat(OS& os)
      << "mat4x3<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat4x3<T,P>(v3_1, v3_2, v3_3, v3_4) << '\n'
      << "mat4x4<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat4x4<T,P>(v4_1, v4_2, v4_3, v4_4) << '\n';
   
-  os << glm::io::column_major
+  os << glm::io::unformatted()
+     << glm::io::order(glm::io::order_type::column_major)
      << "mat2x2<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x2<T,P>(v2_1, v2_2) << '\n'
      << "mat2x3<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x3<T,P>(v3_1, v3_2) << '\n'
      << "mat2x4<" << typeid(T).name() << ',' << P << ">: " << glm::detail::tmat2x4<T,P>(v4_1, v4_2) << '\n'
@@ -126,6 +149,13 @@ int main()
 {
 	int Error(0);
 
+	Error += test_io_quat<float, glm::highp>(std::cout);
+	Error += test_io_quat<float, glm::highp>(std::wcout);
+	Error += test_io_quat<int, glm::mediump>(std::cout);
+	Error += test_io_quat<int, glm::mediump>(std::wcout);
+	Error += test_io_quat<glm::uint, glm::lowp>(std::cout);
+	Error += test_io_quat<glm::uint, glm::lowp>(std::wcout);
+
 	Error += test_io_vec<float, glm::highp>(std::cout);
 	Error += test_io_vec<float, glm::highp>(std::wcout);
 	Error += test_io_vec<int, glm::mediump>(std::cout);