Subject: [boost] [io_base-utilities] Request for interest and/or comments.
From: Vicente J. Botet Escriba (vicente.botet_at_[hidden])
Date: 2012-05-28 09:51:36


Hi,

While refactoring the Boost.Chrono IO (version 2) I've created some
utilities that could be of general use.

* Manipulator Mixin

It is is based on
http://www.angelikalanger.com/Articles/Cuj/05.Manipulators/Manipulators.html.

http://svn.boost.org/svn/boost/trunk/boost/chrono/io/utility/manip_base.hpp
defines a class manip that can be used as follows

     class mendl: public manip<mendl>
     {
     public:
       explicit mendl(size_t how_many) :
         count(how_many) {}
       template <typename out_stream>
       void operator()(out_stream &out) const
       {
         for (size_t line = 0; line < count; ++line)
         {
           out.put(out.widen('\n'));
         }
         out.flush();
       }
     private:
       size_t count;
     };

* std::ios_base Specific Pointers

std::ios_base allows to create specific pointers indexed by xalloc() and
retrieved by pword().

http://svn.boost.org/svn/boost/trunk/boost/chrono/io/utility/ios_base_state_ptr.hpp
defines a class ios_state_ptr class that provides the same interface
that a smart ptr with some minor adaptations to a std::ios_base.

     template <typename Tag, typename T>
     class ios_state_ptr;

The type T must be CopyConstructible. This class must be used as follows

      struct mytag {}
      struct myT {
        int i;
      };

       ios_state_ptr<mytag, myT > ptr(ios);
       if (! ptr) {
         ptr.reset(new myT);
       }
       ptr->i =0;

This class is not thread_safe and should be protected as other io
functions if the user needs to use them in a multi-threaded environment;

The user can use also ios_state_ptr for classes T that are
DefaultConstructible, so that the type is created implicitly if not
already created.

       ios_state_not_null_ptr<mytag, myT > ptr(ios);
       ptr->i =0;

This class is not thread_safe.

Boost.Chrono use it as follows

   namespace chrono {
     namespace detail {
       template<typename CharT>
       struct ios_base_data_aux
       {
         std::basic_string<CharT> time_fmt;
         std::basic_string<CharT> duration_fmt;
       public:

         ios_base_data_aux() :
           time_fmt(""),
           duration_fmt("")
         {}
       };
       template<typename CharT>
       struct ios_base_data {};
     } // namespace detail

     template<typename CharT>
     static inline std::basic_string<CharT> get_time_fmt(std::ios_base &
ios)
     {
       ios_state_not_null_ptr<detail::ios_base_data<CharT>,
detail::ios_base_data_aux<CharT> > ptr(ios);
       return ptr->time_fmt;
     }
     template<typename CharT>
     static inline void set_time_fmt(std::ios_base& ios, std::basic_string<
         CharT> const& fmt)
     {
       ios_state_not_null_ptr<detail::ios_base_data<CharT>,
detail::ios_base_data_aux<CharT> > ptr(ios);
       ptr->time_fmt = fmt;
     }
   }

The internal single call to xalloc should be done before main() to be
thread safe. The library provide a initializer class
xalloc_key_initializer that takes as parameter a tag class.

   namespace chrono { namespace detail {
       namespace /**/ {
         xalloc_key_initializer<detail::ios_base_data<char> >
ios_base_data_aux_xalloc_key_initializer;
         xalloc_key_initializer<detail::ios_base_data<wchar_t> >
wios_base_data_aux_xalloc_key_initializer;
#if BOOST_CHRONO_HAS_UNICODE_SUPPORT
         xalloc_key_initializer<detail::ios_base_data<char16_t> >
u16ios_base_data_aux_xalloc_key_initializer;
         xalloc_key_initializer<detail::ios_base_data<char32_t> >
u32ios_base_data_aux_xalloc_key_initializer;
#endif
       } // namespace
     } }

* ios_flags

ios_base allows also to create specific pointers indexed by xalloc() and
retrieved by iword().

http://svn.boost.org/svn/boost/trunk/boost/chrono/io/utility/ios_base_state_ptr.hpp
defines a class

     template <typename Final>
     class ios_flags;

providing an interface similar to "27.5.3.2 ios_base state functions
[fmtflags.state]

fmtflags flags() const;

Returns: The format control information for both input and output.

fmtflags flags(fmtflags fmtfl);

Postcondition: fmtfl == flags().

Returns: The previous value of flags().

fmtflags setf(fmtflags fmtfl);

Effects: Sets fmtfl in flags().

Returns: The previous value of flags().

fmtflags setf(fmtflags fmtfl, fmtflags mask);

Effects: Clears mask in flags(), sets fmtfl & mask in flags().

Returns: The previous value of flags().

void unsetf(fmtflags mask);

Effects: Clears mask in flags()
"

and that creates implicitly the index of the ios_base::iword() function
once for a specific ios_flags<Final>.

For example, Boost.Chrono use it as follows to store the use_symbol and
use_local flags.

     class fmt_masks : public ios_flags<fmt_masks>
     {
       typedef ios_flags<fmt_masks> base_type;
     public:
       fmt_masks(std::ios_base& ios): base_type(ios) {}
       enum type
       {
         uses_symbol = 1 << 0,
         uses_local = 1 << 1
       };
       duration_style get_duration_style()
       {
         return (flags() & uses_symbol) ? duration_style::symbol :
duration_style::prefix;
       }
       void set_duration_style(duration_style style)
       {
         if (style == duration_style::symbol)
           setf(uses_symbol);
         else
           unsetf(uses_symbol);
       }
       timezone get_timezone()
       {
         return (flags() & uses_local) ? timezone::local : timezone::utc;
       }
       void set_timezone(timezone tz)
       {
         if (tz == timezone::local)
           setf(uses_local);
         else
           unsetf(uses_local);
       }
     };

The internal single call to xalloc should be done before main() to be
thread safe. The library provide a initializer class
     namespace detail
     {
       namespace /**/ {
         xalloc_key_initializer<fmt_masks >
fmt_masks_xalloc_key_initializer;
       } // namespace
     } // namespace detail

Do you see a design flaw on the design of these classes?
Is there an interest to include them in Boost? Could these classes be
associated iostreams?

Best,
Vicente