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