PageRenderTime 449ms CodeModel.GetById 260ms app.highlight 149ms RepoModel.GetById 31ms app.codeStats 1ms

/Src/Dependencies/Boost/boost/xpressive/traits/cpp_regex_traits.hpp

http://hadesmem.googlecode.com/
C++ Header | 694 lines | 436 code | 82 blank | 176 comment | 64 complexity | 64a392aa162883f1b5304d1835f8e2e2 MD5 | raw file
  1///////////////////////////////////////////////////////////////////////////////
  2/// \file cpp_regex_traits.hpp
  3/// Contains the definition of the cpp_regex_traits\<\> template, which is a
  4/// wrapper for std::locale that can be used to customize the behavior of
  5/// static and dynamic regexes.
  6//
  7//  Copyright 2008 Eric Niebler. Distributed under the Boost
  8//  Software License, Version 1.0. (See accompanying file
  9//  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 10
 11#ifndef BOOST_XPRESSIVE_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005
 12#define BOOST_XPRESSIVE_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005
 13
 14// MS compatible compilers support #pragma once
 15#if defined(_MSC_VER) && (_MSC_VER >= 1020)
 16# pragma once
 17#endif
 18
 19#include <ios>
 20#include <string>
 21#include <locale>
 22#include <sstream>
 23#include <boost/config.hpp>
 24#include <boost/assert.hpp>
 25#include <boost/integer.hpp>
 26#include <boost/mpl/assert.hpp>
 27#include <boost/detail/workaround.hpp>
 28#include <boost/type_traits/is_same.hpp>
 29#include <boost/xpressive/detail/detail_fwd.hpp>
 30#include <boost/xpressive/detail/utility/literals.hpp>
 31
 32// From John Maddock:
 33// Fix for gcc prior to 3.4: std::ctype<wchar_t> doesn't allow masks to be combined, for example:
 34// std::use_facet<std::ctype<wchar_t> >(locale()).is(std::ctype_base::lower|std::ctype_base::upper, L'a');
 35// incorrectly returns false.
 36// NOTE: later version of the gcc define __GLIBCXX__, not __GLIBCPP__
 37#if BOOST_WORKAROUND(__GLIBCPP__, != 0)
 38# define BOOST_XPRESSIVE_BUGGY_CTYPE_FACET
 39#endif
 40
 41namespace boost { namespace xpressive
 42{
 43
 44namespace detail
 45{
 46    // define an unsigned integral typedef of the same size as std::ctype_base::mask
 47    typedef boost::uint_t<sizeof(std::ctype_base::mask) * CHAR_BIT>::least umask_t;
 48    BOOST_MPL_ASSERT_RELATION(sizeof(std::ctype_base::mask), ==, sizeof(umask_t));
 49
 50    // Calculate what the size of the umaskex_t type should be to fix the 3 extra bitmasks
 51    //   11 char categories in ctype_base
 52    // +  3 extra categories for xpressive
 53    // = 14 total bits needed
 54    int const umaskex_bits = (14 > (sizeof(umask_t) * CHAR_BIT)) ? 14 : sizeof(umask_t) * CHAR_BIT;
 55
 56    // define an unsigned integral type with at least umaskex_bits
 57    typedef boost::uint_t<umaskex_bits>::fast umaskex_t;
 58    BOOST_MPL_ASSERT_RELATION(sizeof(umask_t), <=, sizeof(umaskex_t));
 59
 60    // cast a ctype mask to a umaskex_t
 61    template<std::ctype_base::mask Mask>
 62    struct mask_cast
 63    {
 64        BOOST_STATIC_CONSTANT(umaskex_t, value = static_cast<umask_t>(Mask));
 65    };
 66
 67    #ifdef __CYGWIN__
 68    // Work around a gcc warning on cygwin
 69    template<>
 70    struct mask_cast<std::ctype_base::print>
 71    {
 72        BOOST_MPL_ASSERT_RELATION('\227', ==, std::ctype_base::print);
 73        BOOST_STATIC_CONSTANT(umaskex_t, value = 0227);
 74    };
 75    #endif
 76
 77    #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
 78    template<std::ctype_base::mask Mask>
 79    umaskex_t const mask_cast<Mask>::value;
 80    #endif
 81
 82    #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET
 83    // an unsigned integer with the highest bit set
 84    umaskex_t const highest_bit = static_cast<umaskex_t>(1) << (sizeof(umaskex_t) * CHAR_BIT - 1);
 85
 86    ///////////////////////////////////////////////////////////////////////////////
 87    // unused_mask
 88    //   find a bit in an int that isn't set
 89    template<umaskex_t In, umaskex_t Out = highest_bit, bool Done = (0 == (Out & In))>
 90    struct unused_mask
 91    {
 92        BOOST_MPL_ASSERT_RELATION(1, !=, Out);
 93        BOOST_STATIC_CONSTANT(umaskex_t, value = (unused_mask<In, (Out >> 1)>::value));
 94    };
 95
 96    template<umaskex_t In, umaskex_t Out>
 97    struct unused_mask<In, Out, true>
 98    {
 99        BOOST_STATIC_CONSTANT(umaskex_t, value = Out);
100    };
101
102    #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION
103    template<umaskex_t In, umaskex_t Out, bool Done>
104    umaskex_t const unused_mask<In, Out, Done>::value;
105    #endif
106
107    umaskex_t const std_ctype_alnum = mask_cast<std::ctype_base::alnum>::value;
108    umaskex_t const std_ctype_alpha = mask_cast<std::ctype_base::alpha>::value;
109    umaskex_t const std_ctype_cntrl = mask_cast<std::ctype_base::cntrl>::value;
110    umaskex_t const std_ctype_digit = mask_cast<std::ctype_base::digit>::value;
111    umaskex_t const std_ctype_graph = mask_cast<std::ctype_base::graph>::value;
112    umaskex_t const std_ctype_lower = mask_cast<std::ctype_base::lower>::value;
113    umaskex_t const std_ctype_print = mask_cast<std::ctype_base::print>::value;
114    umaskex_t const std_ctype_punct = mask_cast<std::ctype_base::punct>::value;
115    umaskex_t const std_ctype_space = mask_cast<std::ctype_base::space>::value;
116    umaskex_t const std_ctype_upper = mask_cast<std::ctype_base::upper>::value;
117    umaskex_t const std_ctype_xdigit = mask_cast<std::ctype_base::xdigit>::value;
118
119    // Reserve some bits for the implementation
120    #if defined(__GLIBCXX__)
121    umaskex_t const std_ctype_reserved = 0x8000;
122    #elif defined(_CPPLIB_VER) && defined(BOOST_WINDOWS)
123    umaskex_t const std_ctype_reserved = 0x8200;
124    #else
125    umaskex_t const std_ctype_reserved = 0;
126    #endif
127
128    // Bitwise-or all the ctype masks together
129    umaskex_t const all_ctype_masks = std_ctype_reserved
130      | std_ctype_alnum | std_ctype_alpha | std_ctype_cntrl | std_ctype_digit
131      | std_ctype_graph | std_ctype_lower | std_ctype_print | std_ctype_punct
132      | std_ctype_space | std_ctype_upper | std_ctype_xdigit;
133
134    // define a new mask for "underscore" ("word" == alnum | underscore)
135    umaskex_t const non_std_ctype_underscore = unused_mask<all_ctype_masks>::value;
136
137    // define a new mask for "blank"
138    umaskex_t const non_std_ctype_blank = unused_mask<all_ctype_masks | non_std_ctype_underscore>::value;
139
140    // define a new mask for "newline"
141    umaskex_t const non_std_ctype_newline = unused_mask<all_ctype_masks | non_std_ctype_underscore | non_std_ctype_blank>::value;
142
143    #else
144    ///////////////////////////////////////////////////////////////////////////////
145    // Ugly work-around for buggy ctype facets.
146    umaskex_t const std_ctype_alnum = 1 << 0;
147    umaskex_t const std_ctype_alpha = 1 << 1;
148    umaskex_t const std_ctype_cntrl = 1 << 2;
149    umaskex_t const std_ctype_digit = 1 << 3;
150    umaskex_t const std_ctype_graph = 1 << 4;
151    umaskex_t const std_ctype_lower = 1 << 5;
152    umaskex_t const std_ctype_print = 1 << 6;
153    umaskex_t const std_ctype_punct = 1 << 7;
154    umaskex_t const std_ctype_space = 1 << 8;
155    umaskex_t const std_ctype_upper = 1 << 9;
156    umaskex_t const std_ctype_xdigit = 1 << 10;
157    umaskex_t const non_std_ctype_underscore = 1 << 11;
158    umaskex_t const non_std_ctype_blank = 1 << 12;
159    umaskex_t const non_std_ctype_newline = 1 << 13;
160
161    static umaskex_t const std_masks[] =
162    {
163        mask_cast<std::ctype_base::alnum>::value
164      , mask_cast<std::ctype_base::alpha>::value
165      , mask_cast<std::ctype_base::cntrl>::value
166      , mask_cast<std::ctype_base::digit>::value
167      , mask_cast<std::ctype_base::graph>::value
168      , mask_cast<std::ctype_base::lower>::value
169      , mask_cast<std::ctype_base::print>::value
170      , mask_cast<std::ctype_base::punct>::value
171      , mask_cast<std::ctype_base::space>::value
172      , mask_cast<std::ctype_base::upper>::value
173      , mask_cast<std::ctype_base::xdigit>::value
174    };
175
176    inline int mylog2(umaskex_t i)
177    {
178        return "\0\0\1\0\2\0\0\0\3"[i & 0xf]
179             + "\0\4\5\0\6\0\0\0\7"[(i & 0xf0) >> 04]
180             + "\0\10\11\0\12\0\0\0\13"[(i & 0xf00) >> 010];
181    }
182    #endif
183
184    // convenient constant for the extra masks
185    umaskex_t const non_std_ctype_masks = non_std_ctype_underscore | non_std_ctype_blank | non_std_ctype_newline;
186
187    ///////////////////////////////////////////////////////////////////////////////
188    // cpp_regex_traits_base
189    //   BUGBUG this should be replaced with a regex facet that lets you query for
190    //   an array of underscore characters and an array of line separator characters.
191    template<typename Char, std::size_t SizeOfChar = sizeof(Char)>
192    struct cpp_regex_traits_base
193    {
194    protected:
195        void imbue(std::locale const &)
196        {
197        }
198
199        static bool is(std::ctype<Char> const &ct, Char ch, umaskex_t mask)
200        {
201            #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET
202
203            if(ct.is((std::ctype_base::mask)(umask_t)mask, ch))
204            {
205                return true;
206            }
207
208            #else
209
210            umaskex_t tmp = mask & ~non_std_ctype_masks;
211            for(umaskex_t i; 0 != (i = (tmp & (~tmp+1))); tmp &= ~i)
212            {
213                std::ctype_base::mask m = (std::ctype_base::mask)(umask_t)std_masks[mylog2(i)];
214                if(ct.is(m, ch))
215                {
216                    return true;
217                }
218            }
219
220            #endif
221
222            return ((mask & non_std_ctype_blank) && cpp_regex_traits_base::is_blank(ch))
223                || ((mask & non_std_ctype_underscore) && cpp_regex_traits_base::is_underscore(ch))
224                || ((mask & non_std_ctype_newline) && cpp_regex_traits_base::is_newline(ch));
225        }
226
227    private:
228        static bool is_blank(Char ch)
229        {
230            BOOST_MPL_ASSERT_RELATION('\t', ==, L'\t');
231            BOOST_MPL_ASSERT_RELATION(' ', ==, L' ');
232            return L' ' == ch || L'\t' == ch;
233        }
234
235        static bool is_underscore(Char ch)
236        {
237            BOOST_MPL_ASSERT_RELATION('_', ==, L'_');
238            return L'_' == ch;
239        }
240
241        static bool is_newline(Char ch)
242        {
243            BOOST_MPL_ASSERT_RELATION('\r', ==, L'\r');
244            BOOST_MPL_ASSERT_RELATION('\n', ==, L'\n');
245            BOOST_MPL_ASSERT_RELATION('\f', ==, L'\f');
246            return L'\r' == ch || L'\n' == ch || L'\f' == ch
247                || (1 < SizeOfChar && (0x2028u == ch || 0x2029u == ch || 0x85u == ch));
248        }
249    };
250
251    #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET
252
253    template<typename Char>
254    struct cpp_regex_traits_base<Char, 1>
255    {
256    protected:
257        void imbue(std::locale const &loc)
258        {
259            int i = 0;
260            Char allchars[UCHAR_MAX + 1];
261            for(i = 0; i <= static_cast<int>(UCHAR_MAX); ++i)
262            {
263                allchars[i] = static_cast<Char>(i);
264            }
265
266            std::ctype<Char> const &ct = BOOST_USE_FACET(std::ctype<Char>, loc);
267            std::ctype_base::mask tmp[UCHAR_MAX + 1];
268            ct.is(allchars, allchars + UCHAR_MAX + 1, tmp);
269            for(i = 0; i <= static_cast<int>(UCHAR_MAX); ++i)
270            {
271                this->masks_[i] = static_cast<umask_t>(tmp[i]);
272                BOOST_ASSERT(0 == (this->masks_[i] & non_std_ctype_masks));
273            }
274
275            this->masks_[static_cast<unsigned char>('_')] |= non_std_ctype_underscore;
276            this->masks_[static_cast<unsigned char>(' ')] |= non_std_ctype_blank;
277            this->masks_[static_cast<unsigned char>('\t')] |= non_std_ctype_blank;
278            this->masks_[static_cast<unsigned char>('\n')] |= non_std_ctype_newline;
279            this->masks_[static_cast<unsigned char>('\r')] |= non_std_ctype_newline;
280            this->masks_[static_cast<unsigned char>('\f')] |= non_std_ctype_newline;
281        }
282
283        bool is(std::ctype<Char> const &, Char ch, umaskex_t mask) const
284        {
285            return 0 != (this->masks_[static_cast<unsigned char>(ch)] & mask);
286        }
287
288    private:
289        umaskex_t masks_[UCHAR_MAX + 1];
290    };
291
292    #endif
293
294} // namespace detail
295
296
297///////////////////////////////////////////////////////////////////////////////
298// cpp_regex_traits
299//
300/// \brief Encapsaulates a std::locale for use by the
301/// basic_regex\<\> class template.
302template<typename Char>
303struct cpp_regex_traits
304  : detail::cpp_regex_traits_base<Char>
305{
306    typedef Char char_type;
307    typedef std::basic_string<char_type> string_type;
308    typedef std::locale locale_type;
309    typedef detail::umaskex_t char_class_type;
310    typedef regex_traits_version_2_tag version_tag;
311    typedef detail::cpp_regex_traits_base<Char> base_type;
312
313    /// Initialize a cpp_regex_traits object to use the specified std::locale,
314    /// or the global std::locale if none is specified.
315    ///
316    cpp_regex_traits(locale_type const &loc = locale_type())
317      : base_type()
318      , loc_()
319    {
320        this->imbue(loc);
321    }
322
323    /// Checks two cpp_regex_traits objects for equality
324    ///
325    /// \return this->getloc() == that.getloc().
326    bool operator ==(cpp_regex_traits<char_type> const &that) const
327    {
328        return this->loc_ == that.loc_;
329    }
330
331    /// Checks two cpp_regex_traits objects for inequality
332    ///
333    /// \return this->getloc() != that.getloc().
334    bool operator !=(cpp_regex_traits<char_type> const &that) const
335    {
336        return this->loc_ != that.loc_;
337    }
338
339    /// Convert a char to a Char
340    ///
341    /// \param ch The source character.
342    /// \return std::use_facet\<std::ctype\<char_type\> \>(this->getloc()).widen(ch).
343    char_type widen(char ch) const
344    {
345        return this->ctype_->widen(ch);
346    }
347
348    /// Returns a hash value for a Char in the range [0, UCHAR_MAX]
349    ///
350    /// \param ch The source character.
351    /// \return a value between 0 and UCHAR_MAX, inclusive.
352    static unsigned char hash(char_type ch)
353    {
354        return static_cast<unsigned char>(std::char_traits<Char>::to_int_type(ch));
355    }
356
357    /// No-op
358    ///
359    /// \param ch The source character.
360    /// \return ch
361    static char_type translate(char_type ch)
362    {
363        return ch;
364    }
365
366    /// Converts a character to lower-case using the internally-stored std::locale.
367    ///
368    /// \param ch The source character.
369    /// \return std::tolower(ch, this->getloc()).
370    char_type translate_nocase(char_type ch) const
371    {
372        return this->ctype_->tolower(ch);
373    }
374
375    /// Converts a character to lower-case using the internally-stored std::locale.
376    ///
377    /// \param ch The source character.
378    /// \return std::tolower(ch, this->getloc()).
379    char_type tolower(char_type ch) const
380    {
381        return this->ctype_->tolower(ch);
382    }
383
384    /// Converts a character to upper-case using the internally-stored std::locale.
385    ///
386    /// \param ch The source character.
387    /// \return std::toupper(ch, this->getloc()).
388    char_type toupper(char_type ch) const
389    {
390        return this->ctype_->toupper(ch);
391    }
392
393    /// Returns a string_type containing all the characters that compare equal
394    /// disregrarding case to the one passed in. This function can only be called
395    /// if has_fold_case\<cpp_regex_traits\<Char\> \>::value is true.
396    ///
397    /// \param ch The source character.
398    /// \return string_type containing all chars which are equal to ch when disregarding
399    ///     case
400    string_type fold_case(char_type ch) const
401    {
402        BOOST_MPL_ASSERT((is_same<char_type, char>));
403        char_type ntcs[] = {
404            this->ctype_->tolower(ch)
405          , this->ctype_->toupper(ch)
406          , 0
407        };
408        if(ntcs[1] == ntcs[0])
409            ntcs[1] = 0;
410        return string_type(ntcs);
411    }
412
413    /// Checks to see if a character is within a character range.
414    ///
415    /// \param first The bottom of the range, inclusive.
416    /// \param last The top of the range, inclusive.
417    /// \param ch The source character.
418    /// \return first <= ch && ch <= last.
419    static bool in_range(char_type first, char_type last, char_type ch)
420    {
421        return first <= ch && ch <= last;
422    }
423
424    /// Checks to see if a character is within a character range, irregardless of case.
425    ///
426    /// \param first The bottom of the range, inclusive.
427    /// \param last The top of the range, inclusive.
428    /// \param ch The source character.
429    /// \return in_range(first, last, ch) || in_range(first, last, tolower(ch, this->getloc())) ||
430    ///     in_range(first, last, toupper(ch, this->getloc()))
431    /// \attention The default implementation doesn't do proper Unicode
432    ///     case folding, but this is the best we can do with the standard
433    ///     ctype facet.
434    bool in_range_nocase(char_type first, char_type last, char_type ch) const
435    {
436        // NOTE: this default implementation doesn't do proper Unicode
437        // case folding, but this is the best we can do with the standard
438        // std::ctype facet.
439        return this->in_range(first, last, ch)
440            || this->in_range(first, last, this->ctype_->toupper(ch))
441            || this->in_range(first, last, this->ctype_->tolower(ch));
442    }
443
444    /// INTERNAL ONLY
445    //string_type transform(char_type const *begin, char_type const *end) const
446    //{
447    //    return this->collate_->transform(begin, end);
448    //}
449
450    /// Returns a sort key for the character sequence designated by the iterator range [F1, F2)
451    /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2)
452    /// then v.transform(G1, G2) \< v.transform(H1, H2).
453    ///
454    /// \attention Not currently used
455    template<typename FwdIter>
456    string_type transform(FwdIter begin, FwdIter end) const
457    {
458        //string_type str(begin, end);
459        //return this->transform(str.data(), str.data() + str.size());
460
461        BOOST_ASSERT(false);
462        return string_type();
463    }
464
465    /// Returns a sort key for the character sequence designated by the iterator range [F1, F2)
466    /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2)
467    /// when character case is not considered then
468    /// v.transform_primary(G1, G2) \< v.transform_primary(H1, H2).
469    ///
470    /// \attention Not currently used
471    template<typename FwdIter>
472    string_type transform_primary(FwdIter begin, FwdIter end) const
473    {
474        BOOST_ASSERT(false); // TODO implement me
475        return string_type();
476    }
477
478    /// Returns a sequence of characters that represents the collating element
479    /// consisting of the character sequence designated by the iterator range [F1, F2).
480    /// Returns an empty string if the character sequence is not a valid collating element.
481    ///
482    /// \attention Not currently used
483    template<typename FwdIter>
484    string_type lookup_collatename(FwdIter begin, FwdIter end) const
485    {
486        BOOST_ASSERT(false); // TODO implement me
487        return string_type();
488    }
489
490    /// For the character class name represented by the specified character sequence,
491    /// return the corresponding bitmask representation.
492    ///
493    /// \param begin A forward iterator to the start of the character sequence representing
494    ///     the name of the character class.
495    /// \param end The end of the character sequence.
496    /// \param icase Specifies whether the returned bitmask should represent the case-insensitive
497    ///     version of the character class.
498    /// \return A bitmask representing the character class.
499    template<typename FwdIter>
500    char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) const
501    {
502        static detail::umaskex_t const icase_masks =
503            detail::std_ctype_lower | detail::std_ctype_upper;
504
505        BOOST_ASSERT(begin != end);
506        char_class_type char_class = this->lookup_classname_impl_(begin, end);
507        if(0 == char_class)
508        {
509            // convert the string to lowercase
510            string_type classname(begin, end);
511            for(typename string_type::size_type i = 0, len = classname.size(); i < len; ++i)
512            {
513                classname[i] = this->translate_nocase(classname[i]);
514            }
515            char_class = this->lookup_classname_impl_(classname.begin(), classname.end());
516        }
517        // erase case-sensitivity if icase==true
518        if(icase && 0 != (char_class & icase_masks))
519        {
520            char_class |= icase_masks;
521        }
522        return char_class;
523    }
524
525    /// Tests a character against a character class bitmask.
526    ///
527    /// \param ch The character to test.
528    /// \param mask The character class bitmask against which to test.
529    /// \pre mask is a bitmask returned by lookup_classname, or is several such masks bit-or'ed
530    ///     together.
531    /// \return true if the character is a member of any of the specified character classes, false
532    ///     otherwise.
533    bool isctype(char_type ch, char_class_type mask) const
534    {
535        return this->base_type::is(*this->ctype_, ch, mask);
536    }
537
538    /// Convert a digit character into the integer it represents.
539    ///
540    /// \param ch The digit character.
541    /// \param radix The radix to use for the conversion.
542    /// \pre radix is one of 8, 10, or 16.
543    /// \return -1 if ch is not a digit character, the integer value of the character otherwise.
544    ///     The conversion is performed by imbueing a std::stringstream with this-\>getloc();
545    ///     setting the radix to one of oct, hex or dec; inserting ch into the stream; and
546    ///     extracting an int.
547    int value(char_type ch, int radix) const
548    {
549        BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix);
550        int val = -1;
551        std::basic_stringstream<char_type> str;
552        str.imbue(this->getloc());
553        str << (8 == radix ? std::oct : (16 == radix ? std::hex : std::dec));
554        str.put(ch);
555        str >> val;
556        return str.fail() ? -1 : val;
557    }
558
559    /// Imbues *this with loc
560    ///
561    /// \param loc A std::locale.
562    /// \return the previous std::locale used by *this.
563    locale_type imbue(locale_type loc)
564    {
565        locale_type old_loc = this->loc_;
566        this->loc_ = loc;
567        this->ctype_ = &BOOST_USE_FACET(std::ctype<char_type>, this->loc_);
568        //this->collate_ = &BOOST_USE_FACET(std::collate<char_type>, this->loc_);
569        this->base_type::imbue(this->loc_);
570        return old_loc;
571    }
572
573    /// Returns the current std::locale used by *this.
574    ///
575    locale_type getloc() const
576    {
577        return this->loc_;
578    }
579
580private:
581
582    ///////////////////////////////////////////////////////////////////////////////
583    // char_class_pair
584    /// INTERNAL ONLY
585    struct char_class_pair
586    {
587        char_type const *class_name_;
588        char_class_type class_type_;
589    };
590
591    ///////////////////////////////////////////////////////////////////////////////
592    // char_class
593    /// INTERNAL ONLY
594    static char_class_pair const &char_class(std::size_t j)
595    {
596        static char_class_pair const s_char_class_map[] =
597        {
598            { BOOST_XPR_CSTR_(char_type, "alnum"),  detail::std_ctype_alnum }
599          , { BOOST_XPR_CSTR_(char_type, "alpha"),  detail::std_ctype_alpha }
600          , { BOOST_XPR_CSTR_(char_type, "blank"),  detail::non_std_ctype_blank }
601          , { BOOST_XPR_CSTR_(char_type, "cntrl"),  detail::std_ctype_cntrl }
602          , { BOOST_XPR_CSTR_(char_type, "d"),      detail::std_ctype_digit }
603          , { BOOST_XPR_CSTR_(char_type, "digit"),  detail::std_ctype_digit }
604          , { BOOST_XPR_CSTR_(char_type, "graph"),  detail::std_ctype_graph }
605          , { BOOST_XPR_CSTR_(char_type, "lower"),  detail::std_ctype_lower }
606          , { BOOST_XPR_CSTR_(char_type, "newline"),detail::non_std_ctype_newline }
607          , { BOOST_XPR_CSTR_(char_type, "print"),  detail::std_ctype_print }
608          , { BOOST_XPR_CSTR_(char_type, "punct"),  detail::std_ctype_punct }
609          , { BOOST_XPR_CSTR_(char_type, "s"),      detail::std_ctype_space }
610          , { BOOST_XPR_CSTR_(char_type, "space"),  detail::std_ctype_space }
611          , { BOOST_XPR_CSTR_(char_type, "upper"),  detail::std_ctype_upper }
612          , { BOOST_XPR_CSTR_(char_type, "w"),      detail::std_ctype_alnum | detail::non_std_ctype_underscore }
613          , { BOOST_XPR_CSTR_(char_type, "xdigit"), detail::std_ctype_xdigit }
614          , { 0, 0 }
615        };
616        return s_char_class_map[j];
617    }
618
619    ///////////////////////////////////////////////////////////////////////////////
620    // lookup_classname_impl
621    /// INTERNAL ONLY
622    template<typename FwdIter>
623    static char_class_type lookup_classname_impl_(FwdIter begin, FwdIter end)
624    {
625        // find the classname
626        typedef cpp_regex_traits<Char> this_t;
627        for(std::size_t j = 0; 0 != this_t::char_class(j).class_name_; ++j)
628        {
629            if(this_t::compare_(this_t::char_class(j).class_name_, begin, end))
630            {
631                return this_t::char_class(j).class_type_;
632            }
633        }
634        return 0;
635    }
636
637    /// INTERNAL ONLY
638    template<typename FwdIter>
639    static bool compare_(char_type const *name, FwdIter begin, FwdIter end)
640    {
641        for(; *name && begin != end; ++name, ++begin)
642        {
643            if(*name != *begin)
644            {
645                return false;
646            }
647        }
648        return !*name && begin == end;
649    }
650
651    locale_type loc_;
652    std::ctype<char_type> const *ctype_;
653    //std::collate<char_type> const *collate_;
654};
655
656///////////////////////////////////////////////////////////////////////////////
657// cpp_regex_traits<>::hash specializations
658template<>
659inline unsigned char cpp_regex_traits<unsigned char>::hash(unsigned char ch)
660{
661    return ch;
662}
663
664template<>
665inline unsigned char cpp_regex_traits<char>::hash(char ch)
666{
667    return static_cast<unsigned char>(ch);
668}
669
670template<>
671inline unsigned char cpp_regex_traits<signed char>::hash(signed char ch)
672{
673    return static_cast<unsigned char>(ch);
674}
675
676#ifndef BOOST_XPRESSIVE_NO_WREGEX
677template<>
678inline unsigned char cpp_regex_traits<wchar_t>::hash(wchar_t ch)
679{
680    return static_cast<unsigned char>(ch);
681}
682#endif
683
684// Narrow C++ traits has fold_case() member function.
685template<>
686struct has_fold_case<cpp_regex_traits<char> >
687  : mpl::true_
688{
689};
690
691
692}}
693
694#endif