// (C) Copyright 2008 CodeRage, LLC (turkanis at coderage dot com)

// (C) Copyright 2003-2007 Jonathan Turkanis

// 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.)



// See http://www.boost.org/libs/iostreams for documentation.



// Contains the definition of the template codecvt_helper, useful for

// defining specializations of std::codecvt where state_type != mbstate_t.

// Compensates for the fact that some standard library implementations 

// do not derive the primiary codecvt template from locale::facet or 

// provide the correct member types and functions.



// Usage: 

//

// // In global namespace:

// BOOST_IOSTREAMS_CODECVT_SPEC(mystate)

//

// // In user namespace:

// template<typename Intern, typename Extern>

// struct mycodecvt : codecvt_helper<Intern, Extern, State> { ... };

//

// // Or:

// struct mycodecvt : codecvt_helper<wchar_t, char, State> { ... };

// 

// Etc.



#ifndef BOOST_IOSTREAMS_DETAIL_CODECVT_HELPER_HPP_INCLUDED

#define BOOST_IOSTREAMS_DETAIL_CODECVT_HELPER_HPP_INCLUDED



#if defined(_MSC_VER) && (_MSC_VER >= 1020)

# pragma once

#endif



#include <boost/config.hpp>  // Put size_t in std, BOOST_MSVC, Dinkum.

#include <boost/detail/workaround.hpp>

#include <algorithm>         // min.

#include <cstddef>           // size_t.

#include <locale>            // locale, codecvt_base, codecvt.

#include <boost/iostreams/detail/config/codecvt.hpp>



//------------------Definition of traits--------------------------------------//



namespace boost { namespace iostreams { namespace detail {



#if !BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) //-----------------------//



template<typename T>

struct codecvt_intern { typedef typename T::intern_type type; };



template<typename T>

struct codecvt_extern { typedef typename T::extern_type type; };



#else // #if !BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) //--------------//



template<typename T>

struct codecvt_intern { typedef typename T::from_type type; };



template<typename T>

struct codecvt_extern { typedef typename T::to_type type; };



#endif // #if !BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, == 1) //-------------//



template<typename T>

struct codecvt_state { typedef typename T::state_type type; };



} } } // End namespaces detail, iostreams, boost.



//------------------Definition of codecvt_impl--------------------------------//



#if defined(BOOST_IOSTREAMS_NO_PRIMARY_CODECVT_DEFINITION) || \

    defined(BOOST_IOSTREAMS_EMPTY_PRIMARY_CODECVT_DEFINITION) || \

    defined(BOOST_IOSTREAMS_NO_LOCALE) \

    /**/



namespace boost { namespace iostreams { namespace detail {



template<typename Intern, typename Extern, typename State>

struct codecvt_impl : std::locale::facet, std::codecvt_base {

public:

    typedef Intern  intern_type;

    typedef Extern  extern_type;

    typedef State   state_type;



    codecvt_impl(std::size_t refs = 0) : std::locale::facet(refs) { } 



    std::codecvt_base::result

    in( State& state, const Extern* first1, const Extern* last1,

        const Extern*& next1, Intern* first2, Intern* last2,

        Intern*& next2 ) const

    {

        return do_in(state, first1, last1, next1, first2, last2, next2);

    }



    std::codecvt_base::result

    out( State& state, const Intern* first1, const Intern* last1,

         const Intern*& next1, Extern* first2, Extern* last2,

         Extern*& next2 ) const

    {

        return do_out(state, first1, last1, next1, first2, last2, next2);

    }



    std::codecvt_base::result

    unshift(State& state, Extern* first2, Extern* last2, Extern*& next2) const

    {

        return do_unshift(state, first2, last2, next2);

    }



    bool always_noconv() const throw() { return do_always_noconv(); }



    int max_length() const throw() { return do_max_length(); }



    int encoding() const throw() { return do_encoding(); }



    int length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER State& state, 

                const Extern* first1, const Extern* last1,

                std::size_t len2 ) const throw()

    {

        return do_length(state, first1, last1, len2);

    }

protected:

    std::codecvt_base::result

    virtual do_in( State&, const Extern*, const Extern*, const Extern*&, 

                   Intern*, Intern*, Intern*& ) const

    {

        return std::codecvt_base::noconv;

    }



    std::codecvt_base::result

    virtual do_out( State&, const Intern*, const Intern*, const Intern*&, 

                    Extern*, Extern*, Extern*& ) const

    {

        return std::codecvt_base::noconv;

    }



    std::codecvt_base::result

    virtual do_unshift( State& state, Extern* first2, Extern* last2, 

                        Extern*& next2 ) const

    {

        return std::codecvt_base::ok;

    }



    virtual bool do_always_noconv() const throw() { return true; }



    virtual int do_max_length() const throw() { return 1; }



    virtual int do_encoding() const throw() { return 1; }



    virtual int do_length( BOOST_IOSTREAMS_CODECVT_CV_QUALIFIER State& state, 

                           const Extern* first1, const Extern* last1,

                           std::size_t len2 ) const throw()

    {

        return (std::min)(static_cast<std::size_t>(last1 - first1), len2);

    }

};



} } } // End namespaces detail, iostreams, boost.



#endif // no primary codecvt definition, empty definition.



//------------------Definition of BOOST_IOSTREAMS_CODECVT_SPEC----------------//



#if defined(BOOST_IOSTREAMS_NO_PRIMARY_CODECVT_DEFINITION) || \

    defined(BOOST_IOSTREAMS_EMPTY_PRIMARY_CODECVT_DEFINITION) \

    /**/

# ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION

#  define BOOST_IOSTREAMS_CODECVT_SPEC(state) \

    namespace std { \

        template<typename Intern, typename Extern> \

        class codecvt<Intern, Extern, state> \

            : public ::boost::iostreams::detail::codecvt_impl< \

                         Intern, Extern, state \

                     > \

        { \

        public: \

            codecvt(std::size_t refs = 0) \

                : ::boost::iostreams::detail::codecvt_impl< \

                      Intern, Extern, state \

                  >(refs) \

                { } \

            static std::locale::id id; \

        }; \

        template<typename Intern, typename Extern> \

        std::locale::id codecvt<Intern, Extern, state>::id; \

    } \

    /**/

# else

#  define BOOST_IOSTREAMS_CODECVT_SPEC(state) \

    namespace std { \

        template<> \

        class codecvt<wchar_t, char, state> \

            : public ::boost::iostreams::detail::codecvt_impl< \

                         wchar_t, char, state \

                     > \

        { \

        public: \

            codecvt(std::size_t refs = 0) \

                : ::boost::iostreams::detail::codecvt_impl< \

                      wchar_t, char, state \

                  >(refs) \

                { } \

            static std::locale::id id; \

        }; \

        template<> \

        std::locale::id codecvt<wchar_t, char, state>::id; \

    } \

    /**/

# endif

#else

# define BOOST_IOSTREAMS_CODECVT_SPEC(state)

#endif // no primary codecvt definition, or empty definition.



namespace boost { namespace iostreams { namespace detail {

                    

//------------------Definition of codecvt_helper------------------------------//



template<typename Intern, typename Extern, typename State>

struct codecvt_helper : std::codecvt<Intern, Extern, State> { 

    typedef Intern  intern_type;

    typedef Extern  extern_type;

    typedef State   state_type;

    codecvt_helper(std::size_t refs = 0) 

    #if !defined(BOOST_IOSTREAMS_NO_CODECVT_CTOR_FROM_SIZE_T)

        : std::codecvt<Intern, Extern, State>(refs)

    #else

        : std::codecvt<Intern, Extern, State>()

    #endif

        { }

#ifdef BOOST_IOSTREAMS_NO_CODECVT_MAX_LENGTH

    int max_length() const throw() { return do_max_length(); }

protected:

    virtual int do_max_length() const throw() { return 1; }

#endif

};



} } } // End namespaces detail, iostreams, boost.



#endif // #ifndef BOOST_IOSTREAMS_DETAIL_CODECVT_HELPER_HPP_INCLUDED

