| /////////////////////////////////////////////////////////////////////////////// |
| /// \file cpp_regex_traits.hpp |
| /// Contains the definition of the cpp_regex_traits\<\> template, which is a |
| /// wrapper for std::locale that can be used to customize the behavior of |
| /// static and dynamic regexes. |
| // |
| // Copyright 2008 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_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005 |
| #define BOOST_XPRESSIVE_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005 |
| |
| // MS compatible compilers support #pragma once |
| #if defined(_MSC_VER) && (_MSC_VER >= 1020) |
| # pragma once |
| #endif |
| |
| #include <ios> |
| #include <string> |
| #include <locale> |
| #include <sstream> |
| #include <boost/config.hpp> |
| #include <boost/assert.hpp> |
| #include <boost/integer.hpp> |
| #include <boost/mpl/assert.hpp> |
| #include <boost/detail/workaround.hpp> |
| #include <boost/type_traits/is_same.hpp> |
| #include <boost/xpressive/detail/detail_fwd.hpp> |
| #include <boost/xpressive/detail/utility/literals.hpp> |
| |
| // From John Maddock: |
| // Fix for gcc prior to 3.4: std::ctype<wchar_t> doesn't allow masks to be combined, for example: |
| // std::use_facet<std::ctype<wchar_t> >(locale()).is(std::ctype_base::lower|std::ctype_base::upper, L'a'); |
| // incorrectly returns false. |
| // NOTE: later version of the gcc define __GLIBCXX__, not __GLIBCPP__ |
| #if BOOST_WORKAROUND(__GLIBCPP__, != 0) |
| # define BOOST_XPRESSIVE_BUGGY_CTYPE_FACET |
| #endif |
| |
| namespace boost { namespace xpressive |
| { |
| |
| namespace detail |
| { |
| // define an unsigned integral typedef of the same size as std::ctype_base::mask |
| typedef boost::uint_t<sizeof(std::ctype_base::mask) * CHAR_BIT>::least umask_t; |
| BOOST_MPL_ASSERT_RELATION(sizeof(std::ctype_base::mask), ==, sizeof(umask_t)); |
| |
| // Calculate what the size of the umaskex_t type should be to fix the 3 extra bitmasks |
| // 11 char categories in ctype_base |
| // + 3 extra categories for xpressive |
| // = 14 total bits needed |
| int const umaskex_bits = (14 > (sizeof(umask_t) * CHAR_BIT)) ? 14 : sizeof(umask_t) * CHAR_BIT; |
| |
| // define an unsigned integral type with at least umaskex_bits |
| typedef boost::uint_t<umaskex_bits>::fast umaskex_t; |
| BOOST_MPL_ASSERT_RELATION(sizeof(umask_t), <=, sizeof(umaskex_t)); |
| |
| // cast a ctype mask to a umaskex_t |
| template<std::ctype_base::mask Mask> |
| struct mask_cast |
| { |
| BOOST_STATIC_CONSTANT(umaskex_t, value = static_cast<umask_t>(Mask)); |
| }; |
| |
| #ifdef __CYGWIN__ |
| // Work around a gcc warning on cygwin |
| template<> |
| struct mask_cast<std::ctype_base::print> |
| { |
| BOOST_MPL_ASSERT_RELATION('\227', ==, std::ctype_base::print); |
| BOOST_STATIC_CONSTANT(umaskex_t, value = 0227); |
| }; |
| #endif |
| |
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
| template<std::ctype_base::mask Mask> |
| umaskex_t const mask_cast<Mask>::value; |
| #endif |
| |
| #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET |
| // an unsigned integer with the highest bit set |
| umaskex_t const highest_bit = static_cast<umaskex_t>(1) << (sizeof(umaskex_t) * CHAR_BIT - 1); |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // unused_mask |
| // find a bit in an int that isn't set |
| template<umaskex_t In, umaskex_t Out = highest_bit, bool Done = (0 == (Out & In))> |
| struct unused_mask |
| { |
| BOOST_MPL_ASSERT_RELATION(1, !=, Out); |
| BOOST_STATIC_CONSTANT(umaskex_t, value = (unused_mask<In, (Out >> 1)>::value)); |
| }; |
| |
| template<umaskex_t In, umaskex_t Out> |
| struct unused_mask<In, Out, true> |
| { |
| BOOST_STATIC_CONSTANT(umaskex_t, value = Out); |
| }; |
| |
| #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION |
| template<umaskex_t In, umaskex_t Out, bool Done> |
| umaskex_t const unused_mask<In, Out, Done>::value; |
| #endif |
| |
| umaskex_t const std_ctype_alnum = mask_cast<std::ctype_base::alnum>::value; |
| umaskex_t const std_ctype_alpha = mask_cast<std::ctype_base::alpha>::value; |
| umaskex_t const std_ctype_cntrl = mask_cast<std::ctype_base::cntrl>::value; |
| umaskex_t const std_ctype_digit = mask_cast<std::ctype_base::digit>::value; |
| umaskex_t const std_ctype_graph = mask_cast<std::ctype_base::graph>::value; |
| umaskex_t const std_ctype_lower = mask_cast<std::ctype_base::lower>::value; |
| umaskex_t const std_ctype_print = mask_cast<std::ctype_base::print>::value; |
| umaskex_t const std_ctype_punct = mask_cast<std::ctype_base::punct>::value; |
| umaskex_t const std_ctype_space = mask_cast<std::ctype_base::space>::value; |
| umaskex_t const std_ctype_upper = mask_cast<std::ctype_base::upper>::value; |
| umaskex_t const std_ctype_xdigit = mask_cast<std::ctype_base::xdigit>::value; |
| |
| // Reserve some bits for the implementation |
| #if defined(__GLIBCXX__) |
| umaskex_t const std_ctype_reserved = 0x8000; |
| #elif defined(_CPPLIB_VER) && defined(BOOST_WINDOWS) |
| umaskex_t const std_ctype_reserved = 0x8200; |
| #else |
| umaskex_t const std_ctype_reserved = 0; |
| #endif |
| |
| // Bitwise-or all the ctype masks together |
| umaskex_t const all_ctype_masks = std_ctype_reserved |
| | std_ctype_alnum | std_ctype_alpha | std_ctype_cntrl | std_ctype_digit |
| | std_ctype_graph | std_ctype_lower | std_ctype_print | std_ctype_punct |
| | std_ctype_space | std_ctype_upper | std_ctype_xdigit; |
| |
| // define a new mask for "underscore" ("word" == alnum | underscore) |
| umaskex_t const non_std_ctype_underscore = unused_mask<all_ctype_masks>::value; |
| |
| // define a new mask for "blank" |
| umaskex_t const non_std_ctype_blank = unused_mask<all_ctype_masks | non_std_ctype_underscore>::value; |
| |
| // define a new mask for "newline" |
| umaskex_t const non_std_ctype_newline = unused_mask<all_ctype_masks | non_std_ctype_underscore | non_std_ctype_blank>::value; |
| |
| #else |
| /////////////////////////////////////////////////////////////////////////////// |
| // Ugly work-around for buggy ctype facets. |
| umaskex_t const std_ctype_alnum = 1 << 0; |
| umaskex_t const std_ctype_alpha = 1 << 1; |
| umaskex_t const std_ctype_cntrl = 1 << 2; |
| umaskex_t const std_ctype_digit = 1 << 3; |
| umaskex_t const std_ctype_graph = 1 << 4; |
| umaskex_t const std_ctype_lower = 1 << 5; |
| umaskex_t const std_ctype_print = 1 << 6; |
| umaskex_t const std_ctype_punct = 1 << 7; |
| umaskex_t const std_ctype_space = 1 << 8; |
| umaskex_t const std_ctype_upper = 1 << 9; |
| umaskex_t const std_ctype_xdigit = 1 << 10; |
| umaskex_t const non_std_ctype_underscore = 1 << 11; |
| umaskex_t const non_std_ctype_blank = 1 << 12; |
| umaskex_t const non_std_ctype_newline = 1 << 13; |
| |
| static umaskex_t const std_masks[] = |
| { |
| mask_cast<std::ctype_base::alnum>::value |
| , mask_cast<std::ctype_base::alpha>::value |
| , mask_cast<std::ctype_base::cntrl>::value |
| , mask_cast<std::ctype_base::digit>::value |
| , mask_cast<std::ctype_base::graph>::value |
| , mask_cast<std::ctype_base::lower>::value |
| , mask_cast<std::ctype_base::print>::value |
| , mask_cast<std::ctype_base::punct>::value |
| , mask_cast<std::ctype_base::space>::value |
| , mask_cast<std::ctype_base::upper>::value |
| , mask_cast<std::ctype_base::xdigit>::value |
| }; |
| |
| inline int mylog2(umaskex_t i) |
| { |
| return "\0\0\1\0\2\0\0\0\3"[i & 0xf] |
| + "\0\4\5\0\6\0\0\0\7"[(i & 0xf0) >> 04] |
| + "\0\10\11\0\12\0\0\0\13"[(i & 0xf00) >> 010]; |
| } |
| #endif |
| |
| // convenient constant for the extra masks |
| umaskex_t const non_std_ctype_masks = non_std_ctype_underscore | non_std_ctype_blank | non_std_ctype_newline; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // cpp_regex_traits_base |
| // BUGBUG this should be replaced with a regex facet that lets you query for |
| // an array of underscore characters and an array of line separator characters. |
| template<typename Char, std::size_t SizeOfChar = sizeof(Char)> |
| struct cpp_regex_traits_base |
| { |
| protected: |
| void imbue(std::locale const &) |
| { |
| } |
| |
| static bool is(std::ctype<Char> const &ct, Char ch, umaskex_t mask) |
| { |
| #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET |
| |
| if(ct.is((std::ctype_base::mask)(umask_t)mask, ch)) |
| { |
| return true; |
| } |
| |
| #else |
| |
| umaskex_t tmp = mask & ~non_std_ctype_masks; |
| for(umaskex_t i; 0 != (i = (tmp & (~tmp+1))); tmp &= ~i) |
| { |
| std::ctype_base::mask m = (std::ctype_base::mask)(umask_t)std_masks[mylog2(i)]; |
| if(ct.is(m, ch)) |
| { |
| return true; |
| } |
| } |
| |
| #endif |
| |
| return ((mask & non_std_ctype_blank) && cpp_regex_traits_base::is_blank(ch)) |
| || ((mask & non_std_ctype_underscore) && cpp_regex_traits_base::is_underscore(ch)) |
| || ((mask & non_std_ctype_newline) && cpp_regex_traits_base::is_newline(ch)); |
| } |
| |
| private: |
| static bool is_blank(Char ch) |
| { |
| BOOST_MPL_ASSERT_RELATION('\t', ==, L'\t'); |
| BOOST_MPL_ASSERT_RELATION(' ', ==, L' '); |
| return L' ' == ch || L'\t' == ch; |
| } |
| |
| static bool is_underscore(Char ch) |
| { |
| BOOST_MPL_ASSERT_RELATION('_', ==, L'_'); |
| return L'_' == ch; |
| } |
| |
| static bool is_newline(Char ch) |
| { |
| BOOST_MPL_ASSERT_RELATION('\r', ==, L'\r'); |
| BOOST_MPL_ASSERT_RELATION('\n', ==, L'\n'); |
| BOOST_MPL_ASSERT_RELATION('\f', ==, L'\f'); |
| return L'\r' == ch || L'\n' == ch || L'\f' == ch |
| || (1 < SizeOfChar && (0x2028u == ch || 0x2029u == ch || 0x85u == ch)); |
| } |
| }; |
| |
| #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET |
| |
| template<typename Char> |
| struct cpp_regex_traits_base<Char, 1> |
| { |
| protected: |
| void imbue(std::locale const &loc) |
| { |
| int i = 0; |
| Char allchars[UCHAR_MAX + 1]; |
| for(i = 0; i <= static_cast<int>(UCHAR_MAX); ++i) |
| { |
| allchars[i] = static_cast<Char>(i); |
| } |
| |
| std::ctype<Char> const &ct = BOOST_USE_FACET(std::ctype<Char>, loc); |
| std::ctype_base::mask tmp[UCHAR_MAX + 1]; |
| ct.is(allchars, allchars + UCHAR_MAX + 1, tmp); |
| for(i = 0; i <= static_cast<int>(UCHAR_MAX); ++i) |
| { |
| this->masks_[i] = static_cast<umask_t>(tmp[i]); |
| BOOST_ASSERT(0 == (this->masks_[i] & non_std_ctype_masks)); |
| } |
| |
| this->masks_[static_cast<unsigned char>('_')] |= non_std_ctype_underscore; |
| this->masks_[static_cast<unsigned char>(' ')] |= non_std_ctype_blank; |
| this->masks_[static_cast<unsigned char>('\t')] |= non_std_ctype_blank; |
| this->masks_[static_cast<unsigned char>('\n')] |= non_std_ctype_newline; |
| this->masks_[static_cast<unsigned char>('\r')] |= non_std_ctype_newline; |
| this->masks_[static_cast<unsigned char>('\f')] |= non_std_ctype_newline; |
| } |
| |
| bool is(std::ctype<Char> const &, Char ch, umaskex_t mask) const |
| { |
| return 0 != (this->masks_[static_cast<unsigned char>(ch)] & mask); |
| } |
| |
| private: |
| umaskex_t masks_[UCHAR_MAX + 1]; |
| }; |
| |
| #endif |
| |
| } // namespace detail |
| |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // cpp_regex_traits |
| // |
| /// \brief Encapsaulates a std::locale for use by the |
| /// basic_regex\<\> class template. |
| template<typename Char> |
| struct cpp_regex_traits |
| : detail::cpp_regex_traits_base<Char> |
| { |
| typedef Char char_type; |
| typedef std::basic_string<char_type> string_type; |
| typedef std::locale locale_type; |
| typedef detail::umaskex_t char_class_type; |
| typedef regex_traits_version_2_tag version_tag; |
| typedef detail::cpp_regex_traits_base<Char> base_type; |
| |
| /// Initialize a cpp_regex_traits object to use the specified std::locale, |
| /// or the global std::locale if none is specified. |
| /// |
| cpp_regex_traits(locale_type const &loc = locale_type()) |
| : base_type() |
| , loc_() |
| { |
| this->imbue(loc); |
| } |
| |
| /// Checks two cpp_regex_traits objects for equality |
| /// |
| /// \return this->getloc() == that.getloc(). |
| bool operator ==(cpp_regex_traits<char_type> const &that) const |
| { |
| return this->loc_ == that.loc_; |
| } |
| |
| /// Checks two cpp_regex_traits objects for inequality |
| /// |
| /// \return this->getloc() != that.getloc(). |
| bool operator !=(cpp_regex_traits<char_type> const &that) const |
| { |
| return this->loc_ != that.loc_; |
| } |
| |
| /// Convert a char to a Char |
| /// |
| /// \param ch The source character. |
| /// \return std::use_facet\<std::ctype\<char_type\> \>(this->getloc()).widen(ch). |
| char_type widen(char ch) const |
| { |
| return this->ctype_->widen(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 internally-stored std::locale. |
| /// |
| /// \param ch The source character. |
| /// \return std::tolower(ch, this->getloc()). |
| char_type translate_nocase(char_type ch) const |
| { |
| return this->ctype_->tolower(ch); |
| } |
| |
| /// Converts a character to lower-case using the internally-stored std::locale. |
| /// |
| /// \param ch The source character. |
| /// \return std::tolower(ch, this->getloc()). |
| char_type tolower(char_type ch) const |
| { |
| return this->ctype_->tolower(ch); |
| } |
| |
| /// Converts a character to upper-case using the internally-stored std::locale. |
| /// |
| /// \param ch The source character. |
| /// \return std::toupper(ch, this->getloc()). |
| char_type toupper(char_type ch) const |
| { |
| return this->ctype_->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\<cpp_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 |
| string_type fold_case(char_type ch) const |
| { |
| BOOST_MPL_ASSERT((is_same<char_type, char>)); |
| char_type ntcs[] = { |
| this->ctype_->tolower(ch) |
| , this->ctype_->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, this->getloc())) || |
| /// in_range(first, last, toupper(ch, this->getloc())) |
| /// \attention The default implementation doesn't do proper Unicode |
| /// case folding, but this is the best we can do with the standard |
| /// ctype facet. |
| bool in_range_nocase(char_type first, char_type last, char_type ch) const |
| { |
| // NOTE: this default implementation doesn't do proper Unicode |
| // case folding, but this is the best we can do with the standard |
| // std::ctype facet. |
| return this->in_range(first, last, ch) |
| || this->in_range(first, last, this->ctype_->toupper(ch)) |
| || this->in_range(first, last, this->ctype_->tolower(ch)); |
| } |
| |
| /// INTERNAL ONLY |
| //string_type transform(char_type const *begin, char_type const *end) const |
| //{ |
| // return this->collate_->transform(begin, end); |
| //} |
| |
| /// 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 currently used |
| template<typename FwdIter> |
| string_type transform(FwdIter begin, FwdIter end) const |
| { |
| //string_type str(begin, end); |
| //return this->transform(str.data(), str.data() + str.size()); |
| |
| BOOST_ASSERT(false); |
| return string_type(); |
| } |
| |
| /// 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 currently used |
| template<typename FwdIter> |
| string_type transform_primary(FwdIter begin, FwdIter end) const |
| { |
| BOOST_ASSERT(false); // TODO implement me |
| return string_type(); |
| } |
| |
| /// 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 currently used |
| template<typename FwdIter> |
| string_type lookup_collatename(FwdIter begin, FwdIter end) const |
| { |
| BOOST_ASSERT(false); // TODO implement me |
| return string_type(); |
| } |
| |
| /// 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> |
| char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) const |
| { |
| static detail::umaskex_t const icase_masks = |
| detail::std_ctype_lower | detail::std_ctype_upper; |
| |
| BOOST_ASSERT(begin != end); |
| char_class_type char_class = this->lookup_classname_impl_(begin, end); |
| if(0 == char_class) |
| { |
| // convert the string to lowercase |
| string_type classname(begin, end); |
| for(typename string_type::size_type i = 0, len = classname.size(); i < len; ++i) |
| { |
| classname[i] = this->translate_nocase(classname[i]); |
| } |
| char_class = this->lookup_classname_impl_(classname.begin(), classname.end()); |
| } |
| // erase case-sensitivity if icase==true |
| if(icase && 0 != (char_class & icase_masks)) |
| { |
| char_class |= icase_masks; |
| } |
| return char_class; |
| } |
| |
| /// 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. |
| bool isctype(char_type ch, char_class_type mask) const |
| { |
| return this->base_type::is(*this->ctype_, 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. |
| /// The conversion is performed by imbueing a std::stringstream with this-\>getloc(); |
| /// setting the radix to one of oct, hex or dec; inserting ch into the stream; and |
| /// extracting an int. |
| int value(char_type ch, int radix) const |
| { |
| BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix); |
| int val = -1; |
| std::basic_stringstream<char_type> str; |
| str.imbue(this->getloc()); |
| str << (8 == radix ? std::oct : (16 == radix ? std::hex : std::dec)); |
| str.put(ch); |
| str >> val; |
| return str.fail() ? -1 : val; |
| } |
| |
| /// Imbues *this with loc |
| /// |
| /// \param loc A std::locale. |
| /// \return the previous std::locale used by *this. |
| locale_type imbue(locale_type loc) |
| { |
| locale_type old_loc = this->loc_; |
| this->loc_ = loc; |
| this->ctype_ = &BOOST_USE_FACET(std::ctype<char_type>, this->loc_); |
| //this->collate_ = &BOOST_USE_FACET(std::collate<char_type>, this->loc_); |
| this->base_type::imbue(this->loc_); |
| return old_loc; |
| } |
| |
| /// Returns the current std::locale used by *this. |
| /// |
| locale_type getloc() const |
| { |
| return this->loc_; |
| } |
| |
| private: |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // char_class_pair |
| /// INTERNAL ONLY |
| struct char_class_pair |
| { |
| char_type const *class_name_; |
| char_class_type class_type_; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // char_class |
| /// INTERNAL ONLY |
| static char_class_pair const &char_class(std::size_t j) |
| { |
| static char_class_pair const s_char_class_map[] = |
| { |
| { BOOST_XPR_CSTR_(char_type, "alnum"), detail::std_ctype_alnum } |
| , { BOOST_XPR_CSTR_(char_type, "alpha"), detail::std_ctype_alpha } |
| , { BOOST_XPR_CSTR_(char_type, "blank"), detail::non_std_ctype_blank } |
| , { BOOST_XPR_CSTR_(char_type, "cntrl"), detail::std_ctype_cntrl } |
| , { BOOST_XPR_CSTR_(char_type, "d"), detail::std_ctype_digit } |
| , { BOOST_XPR_CSTR_(char_type, "digit"), detail::std_ctype_digit } |
| , { BOOST_XPR_CSTR_(char_type, "graph"), detail::std_ctype_graph } |
| , { BOOST_XPR_CSTR_(char_type, "lower"), detail::std_ctype_lower } |
| , { BOOST_XPR_CSTR_(char_type, "newline"),detail::non_std_ctype_newline } |
| , { BOOST_XPR_CSTR_(char_type, "print"), detail::std_ctype_print } |
| , { BOOST_XPR_CSTR_(char_type, "punct"), detail::std_ctype_punct } |
| , { BOOST_XPR_CSTR_(char_type, "s"), detail::std_ctype_space } |
| , { BOOST_XPR_CSTR_(char_type, "space"), detail::std_ctype_space } |
| , { BOOST_XPR_CSTR_(char_type, "upper"), detail::std_ctype_upper } |
| , { BOOST_XPR_CSTR_(char_type, "w"), detail::std_ctype_alnum | detail::non_std_ctype_underscore } |
| , { BOOST_XPR_CSTR_(char_type, "xdigit"), detail::std_ctype_xdigit } |
| , { 0, 0 } |
| }; |
| return s_char_class_map[j]; |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // lookup_classname_impl |
| /// INTERNAL ONLY |
| template<typename FwdIter> |
| static char_class_type lookup_classname_impl_(FwdIter begin, FwdIter end) |
| { |
| // find the classname |
| typedef cpp_regex_traits<Char> this_t; |
| for(std::size_t j = 0; 0 != this_t::char_class(j).class_name_; ++j) |
| { |
| if(this_t::compare_(this_t::char_class(j).class_name_, begin, end)) |
| { |
| return this_t::char_class(j).class_type_; |
| } |
| } |
| return 0; |
| } |
| |
| /// INTERNAL ONLY |
| template<typename FwdIter> |
| static bool compare_(char_type const *name, FwdIter begin, FwdIter end) |
| { |
| for(; *name && begin != end; ++name, ++begin) |
| { |
| if(*name != *begin) |
| { |
| return false; |
| } |
| } |
| return !*name && begin == end; |
| } |
| |
| locale_type loc_; |
| std::ctype<char_type> const *ctype_; |
| //std::collate<char_type> const *collate_; |
| }; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // cpp_regex_traits<>::hash specializations |
| template<> |
| inline unsigned char cpp_regex_traits<unsigned char>::hash(unsigned char ch) |
| { |
| return ch; |
| } |
| |
| template<> |
| inline unsigned char cpp_regex_traits<char>::hash(char ch) |
| { |
| return static_cast<unsigned char>(ch); |
| } |
| |
| template<> |
| inline unsigned char cpp_regex_traits<signed char>::hash(signed char ch) |
| { |
| return static_cast<unsigned char>(ch); |
| } |
| |
| #ifndef BOOST_XPRESSIVE_NO_WREGEX |
| template<> |
| inline unsigned char cpp_regex_traits<wchar_t>::hash(wchar_t ch) |
| { |
| return static_cast<unsigned char>(ch); |
| } |
| #endif |
| |
| // Narrow C++ traits has fold_case() member function. |
| template<> |
| struct has_fold_case<cpp_regex_traits<char> > |
| : mpl::true_ |
| { |
| }; |
| |
| |
| }} |
| |
| #endif |