//////////////////////////////////////////////////////////////////////////////

/// \file c_regex_traits.hpp

/// Contains the definition of the c_regex_traits\<\> template, which is a

/// wrapper for the C locale functions that can be used to customize the

/// behavior of static and dynamic regexes.

//

//  Copyright 2007 Eric Niebler. 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)



#ifndef BOOST_XPRESSIVE_TRAITS_C_REGEX_TRAITS_HPP_EAN_10_04_2005

#define BOOST_XPRESSIVE_TRAITS_C_REGEX_TRAITS_HPP_EAN_10_04_2005



// MS compatible compilers support #pragma once

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

# pragma once

#endif



#include <cstdlib>

#include <boost/config.hpp>

#include <boost/assert.hpp>

#include <boost/xpressive/traits/detail/c_ctype.hpp>



namespace boost { namespace xpressive

{



namespace detail

{

    ///////////////////////////////////////////////////////////////////////////////

    // empty_locale

    struct empty_locale

    {

    };



    ///////////////////////////////////////////////////////////////////////////////

    // c_regex_traits_base

    template<typename Char, std::size_t SizeOfChar = sizeof(Char)>

    struct c_regex_traits_base

    {

    protected:

        template<typename Traits>

        void imbue(Traits const &tr)

        {

        }

    };



    template<typename Char>

    struct c_regex_traits_base<Char, 1>

    {

    protected:

        template<typename Traits>

        static void imbue(Traits const &)

        {

        }

    };



    #ifndef BOOST_XPRESSIVE_NO_WREGEX

    template<std::size_t SizeOfChar>

    struct c_regex_traits_base<wchar_t, SizeOfChar>

    {

    protected:

        template<typename Traits>

        static void imbue(Traits const &)

        {

        }

    };

    #endif



    template<typename Char>

    Char c_tolower(Char);



    template<typename Char>

    Char c_toupper(Char);



    template<>

    inline char c_tolower(char ch)

    {

        using namespace std;

        return static_cast<char>(tolower(static_cast<unsigned char>(ch)));

    }



    template<>

    inline char c_toupper(char ch)

    {

        using namespace std;

        return static_cast<char>(toupper(static_cast<unsigned char>(ch)));

    }



    #ifndef BOOST_XPRESSIVE_NO_WREGEX

    template<>

    inline wchar_t c_tolower(wchar_t ch)

    {

        using namespace std;

        return towlower(ch);

    }



    template<>

    inline wchar_t c_toupper(wchar_t ch)

    {

        using namespace std;

        return towupper(ch);

    }

    #endif



} // namespace detail



///////////////////////////////////////////////////////////////////////////////

// regex_traits_version_1_tag

//

struct regex_traits_version_1_tag;



///////////////////////////////////////////////////////////////////////////////

// c_regex_traits

//

/// \brief Encapsaulates the standard C locale functions for use by the

/// basic_regex\<\> class template.

template<typename Char>

struct c_regex_traits

  : detail::c_regex_traits_base<Char>

{

    typedef Char char_type;

    typedef std::basic_string<char_type> string_type;

    typedef detail::empty_locale locale_type;

    typedef typename detail::char_class_impl<Char>::char_class_type char_class_type;

    typedef regex_traits_version_2_tag version_tag;

    typedef detail::c_regex_traits_base<Char> base_type;



    /// Initialize a c_regex_traits object to use the global C locale.

    ///

    c_regex_traits(locale_type const &loc = locale_type())

      : base_type()

    {

        this->imbue(loc);

    }



    /// Checks two c_regex_traits objects for equality

    ///

    /// \return true.

    bool operator ==(c_regex_traits<char_type> const &) const

    {

        return true;

    }



    /// Checks two c_regex_traits objects for inequality

    ///

    /// \return false.

    bool operator !=(c_regex_traits<char_type> const &) const

    {

        return false;

    }



    /// Convert a char to a Char

    ///

    /// \param ch The source character.

    /// \return ch if Char is char, std::btowc(ch) if Char is wchar_t.

    static char_type widen(char ch);



    /// Returns a hash value for a Char in the range [0, UCHAR_MAX]

    ///

    /// \param ch The source character.

    /// \return a value between 0 and UCHAR_MAX, inclusive.

    static unsigned char hash(char_type ch)

    {

        return static_cast<unsigned char>(std::char_traits<Char>::to_int_type(ch));

    }



    /// No-op

    ///

    /// \param ch The source character.

    /// \return ch

    static char_type translate(char_type ch)

    {

        return ch;

    }



    /// Converts a character to lower-case using the current global C locale.

    ///

    /// \param ch The source character.

    /// \return std::tolower(ch) if Char is char, std::towlower(ch) if Char is wchar_t.

    static char_type translate_nocase(char_type ch)

    {

        return detail::c_tolower(ch);

    }



    /// Converts a character to lower-case using the current global C locale.

    ///

    /// \param ch The source character.

    /// \return std::tolower(ch) if Char is char, std::towlower(ch) if Char is wchar_t.

    static char_type tolower(char_type ch)

    {

        return detail::c_tolower(ch);

    }



    /// Converts a character to upper-case using the current global C locale.

    ///

    /// \param ch The source character.

    /// \return std::toupper(ch) if Char is char, std::towupper(ch) if Char is wchar_t.

    static char_type toupper(char_type ch)

    {

        return detail::c_toupper(ch);

    }



    /// Returns a string_type containing all the characters that compare equal

    /// disregrarding case to the one passed in. This function can only be called

    /// if has_fold_case<c_regex_traits<Char> >::value is true.

    ///

    /// \param ch The source character.

    /// \return string_type containing all chars which are equal to ch when disregarding

    ///     case

    //typedef array<char_type, 2> fold_case_type;

    string_type fold_case(char_type ch) const

    {

        BOOST_MPL_ASSERT((is_same<char_type, char>));

        char_type ntcs[] = {

            detail::c_tolower(ch)

          , detail::c_toupper(ch)

          , 0

        };

        if(ntcs[1] == ntcs[0])

            ntcs[1] = 0;

        return string_type(ntcs);

    }



    /// Checks to see if a character is within a character range.

    ///

    /// \param first The bottom of the range, inclusive.

    /// \param last The top of the range, inclusive.

    /// \param ch The source character.

    /// \return first <= ch && ch <= last.

    static bool in_range(char_type first, char_type last, char_type ch)

    {

        return first <= ch && ch <= last;

    }



    /// Checks to see if a character is within a character range, irregardless of case.

    ///

    /// \param first The bottom of the range, inclusive.

    /// \param last The top of the range, inclusive.

    /// \param ch The source character.

    /// \return in_range(first, last, ch) || in_range(first, last, tolower(ch)) || in_range(first,

    ///     last, toupper(ch))

    /// \attention The default implementation doesn't do proper Unicode

    ///     case folding, but this is the best we can do with the standard

    ///     C locale functions.

    static bool in_range_nocase(char_type first, char_type last, char_type ch)

    {

        return c_regex_traits::in_range(first, last, ch)

            || c_regex_traits::in_range(first, last, detail::c_tolower(ch))

            || c_regex_traits::in_range(first, last, detail::c_toupper(ch));

    }



    /// Returns a sort key for the character sequence designated by the iterator range [F1, F2)

    /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2)

    /// then v.transform(G1, G2) < v.transform(H1, H2).

    ///

    /// \attention Not used in xpressive 1.0

    template<typename FwdIter>

    static string_type transform(FwdIter begin, FwdIter end)

    {

        BOOST_ASSERT(false); // BUGBUG implement me

    }



    /// Returns a sort key for the character sequence designated by the iterator range [F1, F2)

    /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2)

    /// when character case is not considered then

    /// v.transform_primary(G1, G2) < v.transform_primary(H1, H2).

    ///

    /// \attention Not used in xpressive 1.0

    template<typename FwdIter>

    static string_type transform_primary(FwdIter begin, FwdIter end)

    {

        BOOST_ASSERT(false); // BUGBUG implement me

    }



    /// Returns a sequence of characters that represents the collating element

    /// consisting of the character sequence designated by the iterator range [F1, F2).

    /// Returns an empty string if the character sequence is not a valid collating element.

    ///

    /// \attention Not used in xpressive 1.0

    template<typename FwdIter>

    static string_type lookup_collatename(FwdIter begin, FwdIter end)

    {

        BOOST_ASSERT(false); // BUGBUG implement me

    }



    /// For the character class name represented by the specified character sequence,

    /// return the corresponding bitmask representation.

    ///

    /// \param begin A forward iterator to the start of the character sequence representing

    ///     the name of the character class.

    /// \param end The end of the character sequence.

    /// \param icase Specifies whether the returned bitmask should represent the case-insensitive

    ///     version of the character class.

    /// \return A bitmask representing the character class.

    template<typename FwdIter>

    static char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase)

    {

        return detail::char_class_impl<char_type>::lookup_classname(begin, end, icase);

    }



    /// Tests a character against a character class bitmask.

    ///

    /// \param ch The character to test.

    /// \param mask The character class bitmask against which to test.

    /// \pre mask is a bitmask returned by lookup_classname, or is several such masks bit-or'ed

    ///     together.

    /// \return true if the character is a member of any of the specified character classes, false

    ///     otherwise.

    static bool isctype(char_type ch, char_class_type mask)

    {

        return detail::char_class_impl<char_type>::isctype(ch, mask);

    }



    /// Convert a digit character into the integer it represents.

    ///

    /// \param ch The digit character.

    /// \param radix The radix to use for the conversion.

    /// \pre radix is one of 8, 10, or 16.

    /// \return -1 if ch is not a digit character, the integer value of the character otherwise. If

    ///     char_type is char, std::strtol is used for the conversion. If char_type is wchar_t,

    ///     std::wcstol is used.

    static int value(char_type ch, int radix);



    /// No-op

    ///

    locale_type imbue(locale_type loc)

    {

        this->base_type::imbue(*this);

        return loc;

    }



    /// No-op

    ///

    static locale_type getloc()

    {

        locale_type loc;

        return loc;

    }

};



///////////////////////////////////////////////////////////////////////////////

// c_regex_traits<>::widen specializations

/// INTERNAL ONLY

template<>

inline char c_regex_traits<char>::widen(char ch)

{

    return ch;

}



#ifndef BOOST_XPRESSIVE_NO_WREGEX

/// INTERNAL ONLY

template<>

inline wchar_t c_regex_traits<wchar_t>::widen(char ch)

{

    using namespace std;

    return btowc(ch);

}

#endif



///////////////////////////////////////////////////////////////////////////////

// c_regex_traits<>::hash specializations

/// INTERNAL ONLY

template<>

inline unsigned char c_regex_traits<char>::hash(char ch)

{

    return static_cast<unsigned char>(ch);

}



#ifndef BOOST_XPRESSIVE_NO_WREGEX

/// INTERNAL ONLY

template<>

inline unsigned char c_regex_traits<wchar_t>::hash(wchar_t ch)

{

    return static_cast<unsigned char>(ch);

}

#endif



///////////////////////////////////////////////////////////////////////////////

// c_regex_traits<>::value specializations

/// INTERNAL ONLY

template<>

inline int c_regex_traits<char>::value(char ch, int radix)

{

    using namespace std;

    BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix);

    char begin[2] = { ch, '\0' }, *end = 0;

    int val = strtol(begin, &end, radix);

    return begin == end ? -1 : val;

}



#ifndef BOOST_XPRESSIVE_NO_WREGEX

/// INTERNAL ONLY

template<>

inline int c_regex_traits<wchar_t>::value(wchar_t ch, int radix)

{

    using namespace std;

    BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix);

    wchar_t begin[2] = { ch, L'\0' }, *end = 0;

    int val = wcstol(begin, &end, radix);

    return begin == end ? -1 : val;

}

#endif



// Narrow C traits has fold_case() member function.

template<>

struct has_fold_case<c_regex_traits<char> >

  : mpl::true_

{

};



}}



#endif

