Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: /// \file cpp_regex_traits.hpp Chris@16: /// Contains the definition of the cpp_regex_traits\<\> template, which is a Chris@16: /// wrapper for std::locale that can be used to customize the behavior of Chris@16: /// static and dynamic regexes. Chris@16: // Chris@16: // Copyright 2008 Eric Niebler. Distributed under the Boost Chris@16: // Software License, Version 1.0. (See accompanying file Chris@16: // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #ifndef BOOST_XPRESSIVE_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005 Chris@16: #define BOOST_XPRESSIVE_TRAITS_CPP_REGEX_TRAITS_HPP_EAN_10_04_2005 Chris@16: Chris@16: // MS compatible compilers support #pragma once Chris@101: #if defined(_MSC_VER) Chris@16: # pragma once Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: // From John Maddock: Chris@16: // Fix for gcc prior to 3.4: std::ctype doesn't allow masks to be combined, for example: Chris@16: // std::use_facet >(locale()).is(std::ctype_base::lower|std::ctype_base::upper, L'a'); Chris@16: // incorrectly returns false. Chris@16: // NOTE: later version of the gcc define __GLIBCXX__, not __GLIBCPP__ Chris@16: #if BOOST_WORKAROUND(__GLIBCPP__, != 0) Chris@16: # define BOOST_XPRESSIVE_BUGGY_CTYPE_FACET Chris@16: #endif Chris@16: Chris@16: namespace boost { namespace xpressive Chris@16: { Chris@16: Chris@16: namespace detail Chris@16: { Chris@16: // define an unsigned integral typedef of the same size as std::ctype_base::mask Chris@16: typedef boost::uint_t::least umask_t; Chris@16: BOOST_MPL_ASSERT_RELATION(sizeof(std::ctype_base::mask), ==, sizeof(umask_t)); Chris@16: Chris@16: // Calculate what the size of the umaskex_t type should be to fix the 3 extra bitmasks Chris@16: // 11 char categories in ctype_base Chris@16: // + 3 extra categories for xpressive Chris@16: // = 14 total bits needed Chris@16: int const umaskex_bits = (14 > (sizeof(umask_t) * CHAR_BIT)) ? 14 : sizeof(umask_t) * CHAR_BIT; Chris@16: Chris@16: // define an unsigned integral type with at least umaskex_bits Chris@16: typedef boost::uint_t::fast umaskex_t; Chris@16: BOOST_MPL_ASSERT_RELATION(sizeof(umask_t), <=, sizeof(umaskex_t)); Chris@16: Chris@16: // cast a ctype mask to a umaskex_t Chris@16: template Chris@16: struct mask_cast Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(umaskex_t, value = static_cast(Mask)); Chris@16: }; Chris@16: Chris@16: #ifdef __CYGWIN__ Chris@16: // Work around a gcc warning on cygwin Chris@16: template<> Chris@16: struct mask_cast Chris@16: { Chris@16: BOOST_MPL_ASSERT_RELATION('\227', ==, std::ctype_base::print); Chris@16: BOOST_STATIC_CONSTANT(umaskex_t, value = 0227); Chris@16: }; Chris@16: #endif Chris@16: Chris@16: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@16: template Chris@16: umaskex_t const mask_cast::value; Chris@16: #endif Chris@16: Chris@16: #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET Chris@16: // an unsigned integer with the highest bit set Chris@16: umaskex_t const highest_bit = static_cast(1) << (sizeof(umaskex_t) * CHAR_BIT - 1); Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // unused_mask Chris@16: // find a bit in an int that isn't set Chris@16: template Chris@16: struct unused_mask Chris@16: { Chris@16: BOOST_STATIC_ASSERT(1 != Out); Chris@16: BOOST_STATIC_CONSTANT(umaskex_t, value = (unused_mask> 1)>::value)); Chris@16: }; Chris@16: Chris@16: template Chris@16: struct unused_mask Chris@16: { Chris@16: BOOST_STATIC_CONSTANT(umaskex_t, value = Out); Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION Chris@16: template Chris@16: umaskex_t const unused_mask::value; Chris@16: #endif Chris@16: Chris@16: umaskex_t const std_ctype_alnum = mask_cast::value; Chris@16: umaskex_t const std_ctype_alpha = mask_cast::value; Chris@16: umaskex_t const std_ctype_cntrl = mask_cast::value; Chris@16: umaskex_t const std_ctype_digit = mask_cast::value; Chris@16: umaskex_t const std_ctype_graph = mask_cast::value; Chris@16: umaskex_t const std_ctype_lower = mask_cast::value; Chris@16: umaskex_t const std_ctype_print = mask_cast::value; Chris@16: umaskex_t const std_ctype_punct = mask_cast::value; Chris@16: umaskex_t const std_ctype_space = mask_cast::value; Chris@16: umaskex_t const std_ctype_upper = mask_cast::value; Chris@16: umaskex_t const std_ctype_xdigit = mask_cast::value; Chris@16: Chris@16: // Reserve some bits for the implementation Chris@16: #if defined(__GLIBCXX__) Chris@16: umaskex_t const std_ctype_reserved = 0x8000; Chris@16: #elif defined(_CPPLIB_VER) && defined(BOOST_WINDOWS) Chris@16: umaskex_t const std_ctype_reserved = 0x8200; Chris@16: #elif defined(_LIBCPP_VERSION) Chris@16: umaskex_t const std_ctype_reserved = 0x8000; Chris@16: #else Chris@16: umaskex_t const std_ctype_reserved = 0; Chris@16: #endif Chris@16: Chris@16: // Bitwise-or all the ctype masks together Chris@16: umaskex_t const all_ctype_masks = std_ctype_reserved Chris@16: | std_ctype_alnum | std_ctype_alpha | std_ctype_cntrl | std_ctype_digit Chris@16: | std_ctype_graph | std_ctype_lower | std_ctype_print | std_ctype_punct Chris@16: | std_ctype_space | std_ctype_upper | std_ctype_xdigit; Chris@16: Chris@16: // define a new mask for "underscore" ("word" == alnum | underscore) Chris@16: umaskex_t const non_std_ctype_underscore = unused_mask::value; Chris@16: Chris@16: // define a new mask for "blank" Chris@16: umaskex_t const non_std_ctype_blank = unused_mask::value; Chris@16: Chris@16: // define a new mask for "newline" Chris@16: umaskex_t const non_std_ctype_newline = unused_mask::value; Chris@16: Chris@16: #else Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // Ugly work-around for buggy ctype facets. Chris@16: umaskex_t const std_ctype_alnum = 1 << 0; Chris@16: umaskex_t const std_ctype_alpha = 1 << 1; Chris@16: umaskex_t const std_ctype_cntrl = 1 << 2; Chris@16: umaskex_t const std_ctype_digit = 1 << 3; Chris@16: umaskex_t const std_ctype_graph = 1 << 4; Chris@16: umaskex_t const std_ctype_lower = 1 << 5; Chris@16: umaskex_t const std_ctype_print = 1 << 6; Chris@16: umaskex_t const std_ctype_punct = 1 << 7; Chris@16: umaskex_t const std_ctype_space = 1 << 8; Chris@16: umaskex_t const std_ctype_upper = 1 << 9; Chris@16: umaskex_t const std_ctype_xdigit = 1 << 10; Chris@16: umaskex_t const non_std_ctype_underscore = 1 << 11; Chris@16: umaskex_t const non_std_ctype_blank = 1 << 12; Chris@16: umaskex_t const non_std_ctype_newline = 1 << 13; Chris@16: Chris@16: static umaskex_t const std_masks[] = Chris@16: { Chris@16: mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: , mask_cast::value Chris@16: }; Chris@16: Chris@16: inline int mylog2(umaskex_t i) Chris@16: { Chris@16: return "\0\0\1\0\2\0\0\0\3"[i & 0xf] Chris@16: + "\0\4\5\0\6\0\0\0\7"[(i & 0xf0) >> 04] Chris@16: + "\0\10\11\0\12\0\0\0\13"[(i & 0xf00) >> 010]; Chris@16: } Chris@16: #endif Chris@16: Chris@16: // convenient constant for the extra masks Chris@16: umaskex_t const non_std_ctype_masks = non_std_ctype_underscore | non_std_ctype_blank | non_std_ctype_newline; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // cpp_regex_traits_base Chris@16: // BUGBUG this should be replaced with a regex facet that lets you query for Chris@16: // an array of underscore characters and an array of line separator characters. Chris@16: template Chris@16: struct cpp_regex_traits_base Chris@16: { Chris@16: protected: Chris@16: void imbue(std::locale const &) Chris@16: { Chris@16: } Chris@16: Chris@16: static bool is(std::ctype const &ct, Char ch, umaskex_t mask) Chris@16: { Chris@16: #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET Chris@16: Chris@16: if(ct.is((std::ctype_base::mask)(umask_t)mask, ch)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: Chris@16: // HACKHACK Cygwin and mingw have buggy ctype facets for wchar_t Chris@16: #if defined(__CYGWIN__) || defined(__MINGW32_VERSION) Chris@16: if (std::ctype_base::xdigit == ((std::ctype_base::mask)(umask_t)mask & std::ctype_base::xdigit)) Chris@16: { Chris@16: typename std::char_traits::int_type i = std::char_traits::to_int_type(ch); Chris@16: if(UCHAR_MAX >= i && std::isxdigit(static_cast(i))) Chris@16: return true; Chris@16: } Chris@16: #endif Chris@16: Chris@16: #else Chris@16: Chris@16: umaskex_t tmp = mask & ~non_std_ctype_masks; Chris@16: for(umaskex_t i; 0 != (i = (tmp & (~tmp+1))); tmp &= ~i) Chris@16: { Chris@16: std::ctype_base::mask m = (std::ctype_base::mask)(umask_t)std_masks[mylog2(i)]; Chris@16: if(ct.is(m, ch)) Chris@16: { Chris@16: return true; Chris@16: } Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: return ((mask & non_std_ctype_blank) && cpp_regex_traits_base::is_blank(ch)) Chris@16: || ((mask & non_std_ctype_underscore) && cpp_regex_traits_base::is_underscore(ch)) Chris@16: || ((mask & non_std_ctype_newline) && cpp_regex_traits_base::is_newline(ch)); Chris@16: } Chris@16: Chris@16: private: Chris@16: static bool is_blank(Char ch) Chris@16: { Chris@16: BOOST_MPL_ASSERT_RELATION('\t', ==, L'\t'); Chris@16: BOOST_MPL_ASSERT_RELATION(' ', ==, L' '); Chris@16: return L' ' == ch || L'\t' == ch; Chris@16: } Chris@16: Chris@16: static bool is_underscore(Char ch) Chris@16: { Chris@16: BOOST_MPL_ASSERT_RELATION('_', ==, L'_'); Chris@16: return L'_' == ch; Chris@16: } Chris@16: Chris@16: static bool is_newline(Char ch) Chris@16: { Chris@16: BOOST_MPL_ASSERT_RELATION('\r', ==, L'\r'); Chris@16: BOOST_MPL_ASSERT_RELATION('\n', ==, L'\n'); Chris@16: BOOST_MPL_ASSERT_RELATION('\f', ==, L'\f'); Chris@16: return L'\r' == ch || L'\n' == ch || L'\f' == ch Chris@16: || (1 < SizeOfChar && (0x2028u == ch || 0x2029u == ch || 0x85u == ch)); Chris@16: } Chris@16: }; Chris@16: Chris@16: #ifndef BOOST_XPRESSIVE_BUGGY_CTYPE_FACET Chris@16: Chris@16: template Chris@16: struct cpp_regex_traits_base Chris@16: { Chris@16: protected: Chris@16: void imbue(std::locale const &loc) Chris@16: { Chris@16: int i = 0; Chris@16: Char allchars[UCHAR_MAX + 1]; Chris@16: for(i = 0; i <= static_cast(UCHAR_MAX); ++i) Chris@16: { Chris@16: allchars[i] = static_cast(i); Chris@16: } Chris@16: Chris@16: std::ctype const &ct = BOOST_USE_FACET(std::ctype, loc); Chris@16: std::ctype_base::mask tmp[UCHAR_MAX + 1]; Chris@16: ct.is(allchars, allchars + UCHAR_MAX + 1, tmp); Chris@16: for(i = 0; i <= static_cast(UCHAR_MAX); ++i) Chris@16: { Chris@16: this->masks_[i] = static_cast(tmp[i]); Chris@16: BOOST_ASSERT(0 == (this->masks_[i] & non_std_ctype_masks)); Chris@16: } Chris@16: Chris@16: this->masks_[static_cast('_')] |= non_std_ctype_underscore; Chris@16: this->masks_[static_cast(' ')] |= non_std_ctype_blank; Chris@16: this->masks_[static_cast('\t')] |= non_std_ctype_blank; Chris@16: this->masks_[static_cast('\n')] |= non_std_ctype_newline; Chris@16: this->masks_[static_cast('\r')] |= non_std_ctype_newline; Chris@16: this->masks_[static_cast('\f')] |= non_std_ctype_newline; Chris@16: } Chris@16: Chris@16: bool is(std::ctype const &, Char ch, umaskex_t mask) const Chris@16: { Chris@16: return 0 != (this->masks_[static_cast(ch)] & mask); Chris@16: } Chris@16: Chris@16: private: Chris@16: umaskex_t masks_[UCHAR_MAX + 1]; Chris@16: }; Chris@16: Chris@16: #endif Chris@16: Chris@16: } // namespace detail Chris@16: Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // cpp_regex_traits Chris@16: // Chris@16: /// \brief Encapsaulates a \c std::locale for use by the Chris@16: /// \c basic_regex\<\> class template. Chris@16: template Chris@16: struct cpp_regex_traits Chris@16: : detail::cpp_regex_traits_base Chris@16: { Chris@16: typedef Char char_type; Chris@16: typedef std::basic_string string_type; Chris@16: typedef std::locale locale_type; Chris@16: typedef detail::umaskex_t char_class_type; Chris@16: typedef regex_traits_version_2_tag version_tag; Chris@16: typedef detail::cpp_regex_traits_base base_type; Chris@16: Chris@16: /// Initialize a cpp_regex_traits object to use the specified std::locale, Chris@16: /// or the global std::locale if none is specified. Chris@16: /// Chris@16: cpp_regex_traits(locale_type const &loc = locale_type()) Chris@16: : base_type() Chris@16: , loc_() Chris@16: { Chris@16: this->imbue(loc); Chris@16: } Chris@16: Chris@16: /// Checks two cpp_regex_traits objects for equality Chris@16: /// Chris@16: /// \return this->getloc() == that.getloc(). Chris@16: bool operator ==(cpp_regex_traits const &that) const Chris@16: { Chris@16: return this->loc_ == that.loc_; Chris@16: } Chris@16: Chris@16: /// Checks two cpp_regex_traits objects for inequality Chris@16: /// Chris@16: /// \return this->getloc() != that.getloc(). Chris@16: bool operator !=(cpp_regex_traits const &that) const Chris@16: { Chris@16: return this->loc_ != that.loc_; Chris@16: } Chris@16: Chris@16: /// Convert a char to a Char Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return std::use_facet\ \>(this->getloc()).widen(ch). Chris@16: char_type widen(char ch) const Chris@16: { Chris@16: return this->ctype_->widen(ch); Chris@16: } Chris@16: Chris@16: /// Returns a hash value for a Char in the range [0, UCHAR_MAX] Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return a value between 0 and UCHAR_MAX, inclusive. Chris@16: static unsigned char hash(char_type ch) Chris@16: { Chris@16: return static_cast(std::char_traits::to_int_type(ch)); Chris@16: } Chris@16: Chris@16: /// No-op Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return ch Chris@16: static char_type translate(char_type ch) Chris@16: { Chris@16: return ch; Chris@16: } Chris@16: Chris@16: /// Converts a character to lower-case using the internally-stored std::locale. Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return std::tolower(ch, this->getloc()). Chris@16: char_type translate_nocase(char_type ch) const Chris@16: { Chris@16: return this->ctype_->tolower(ch); Chris@16: } Chris@16: Chris@16: /// Converts a character to lower-case using the internally-stored std::locale. Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return std::tolower(ch, this->getloc()). Chris@16: char_type tolower(char_type ch) const Chris@16: { Chris@16: return this->ctype_->tolower(ch); Chris@16: } Chris@16: Chris@16: /// Converts a character to upper-case using the internally-stored std::locale. Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return std::toupper(ch, this->getloc()). Chris@16: char_type toupper(char_type ch) const Chris@16: { Chris@16: return this->ctype_->toupper(ch); Chris@16: } Chris@16: Chris@16: /// Returns a \c string_type containing all the characters that compare equal Chris@16: /// disregrarding case to the one passed in. This function can only be called Chris@16: /// if has_fold_case\ \>::value is \c true. Chris@16: /// Chris@16: /// \param ch The source character. Chris@16: /// \return \c string_type containing all chars which are equal to \c ch when disregarding Chris@16: /// case Chris@16: string_type fold_case(char_type ch) const Chris@16: { Chris@16: BOOST_MPL_ASSERT((is_same)); Chris@16: char_type ntcs[] = { Chris@16: this->ctype_->tolower(ch) Chris@16: , this->ctype_->toupper(ch) Chris@16: , 0 Chris@16: }; Chris@16: if(ntcs[1] == ntcs[0]) Chris@16: ntcs[1] = 0; Chris@16: return string_type(ntcs); Chris@16: } Chris@16: Chris@16: /// Checks to see if a character is within a character range. Chris@16: /// Chris@16: /// \param first The bottom of the range, inclusive. Chris@16: /// \param last The top of the range, inclusive. Chris@16: /// \param ch The source character. Chris@16: /// \return first <= ch && ch <= last. Chris@16: static bool in_range(char_type first, char_type last, char_type ch) Chris@16: { Chris@16: return first <= ch && ch <= last; Chris@16: } Chris@16: Chris@16: /// Checks to see if a character is within a character range, irregardless of case. Chris@16: /// Chris@16: /// \param first The bottom of the range, inclusive. Chris@16: /// \param last The top of the range, inclusive. Chris@16: /// \param ch The source character. Chris@16: /// \return in_range(first, last, ch) || in_range(first, last, tolower(ch, this->getloc())) || Chris@16: /// in_range(first, last, toupper(ch, this->getloc())) Chris@16: /// \attention The default implementation doesn't do proper Unicode Chris@16: /// case folding, but this is the best we can do with the standard Chris@16: /// ctype facet. Chris@16: bool in_range_nocase(char_type first, char_type last, char_type ch) const Chris@16: { Chris@16: // NOTE: this default implementation doesn't do proper Unicode Chris@16: // case folding, but this is the best we can do with the standard Chris@16: // std::ctype facet. Chris@16: return this->in_range(first, last, ch) Chris@16: || this->in_range(first, last, this->ctype_->toupper(ch)) Chris@16: || this->in_range(first, last, this->ctype_->tolower(ch)); Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: //string_type transform(char_type const *begin, char_type const *end) const Chris@16: //{ Chris@16: // return this->collate_->transform(begin, end); Chris@16: //} Chris@16: Chris@16: /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) Chris@16: /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) Chris@16: /// then v.transform(G1, G2) \< v.transform(H1, H2). Chris@16: /// Chris@16: /// \attention Not currently used Chris@16: template Chris@16: string_type transform(FwdIter, FwdIter) const Chris@16: { Chris@16: //string_type str(begin, end); Chris@16: //return this->transform(str.data(), str.data() + str.size()); Chris@16: Chris@16: BOOST_ASSERT(false); Chris@16: return string_type(); Chris@16: } Chris@16: Chris@16: /// Returns a sort key for the character sequence designated by the iterator range [F1, F2) Chris@16: /// such that if the character sequence [G1, G2) sorts before the character sequence [H1, H2) Chris@16: /// when character case is not considered then Chris@16: /// v.transform_primary(G1, G2) \< v.transform_primary(H1, H2). Chris@16: /// Chris@16: /// \attention Not currently used Chris@16: template Chris@16: string_type transform_primary(FwdIter, FwdIter ) const Chris@16: { Chris@16: BOOST_ASSERT(false); // TODO implement me Chris@16: return string_type(); Chris@16: } Chris@16: Chris@16: /// Returns a sequence of characters that represents the collating element Chris@16: /// consisting of the character sequence designated by the iterator range [F1, F2). Chris@16: /// Returns an empty string if the character sequence is not a valid collating element. Chris@16: /// Chris@16: /// \attention Not currently used Chris@16: template Chris@16: string_type lookup_collatename(FwdIter, FwdIter) const Chris@16: { Chris@16: BOOST_ASSERT(false); // TODO implement me Chris@16: return string_type(); Chris@16: } Chris@16: Chris@16: /// For the character class name represented by the specified character sequence, Chris@16: /// return the corresponding bitmask representation. Chris@16: /// Chris@16: /// \param begin A forward iterator to the start of the character sequence representing Chris@16: /// the name of the character class. Chris@16: /// \param end The end of the character sequence. Chris@16: /// \param icase Specifies whether the returned bitmask should represent the case-insensitive Chris@16: /// version of the character class. Chris@16: /// \return A bitmask representing the character class. Chris@16: template Chris@16: char_class_type lookup_classname(FwdIter begin, FwdIter end, bool icase) const Chris@16: { Chris@16: static detail::umaskex_t const icase_masks = Chris@16: detail::std_ctype_lower | detail::std_ctype_upper; Chris@16: Chris@16: BOOST_ASSERT(begin != end); Chris@16: char_class_type char_class = this->lookup_classname_impl_(begin, end); Chris@16: if(0 == char_class) Chris@16: { Chris@16: // convert the string to lowercase Chris@16: string_type classname(begin, end); Chris@16: for(typename string_type::size_type i = 0, len = classname.size(); i < len; ++i) Chris@16: { Chris@16: classname[i] = this->translate_nocase(classname[i]); Chris@16: } Chris@16: char_class = this->lookup_classname_impl_(classname.begin(), classname.end()); Chris@16: } Chris@16: // erase case-sensitivity if icase==true Chris@16: if(icase && 0 != (char_class & icase_masks)) Chris@16: { Chris@16: char_class |= icase_masks; Chris@16: } Chris@16: return char_class; Chris@16: } Chris@16: Chris@16: /// Tests a character against a character class bitmask. Chris@16: /// Chris@16: /// \param ch The character to test. Chris@16: /// \param mask The character class bitmask against which to test. Chris@16: /// \pre mask is a bitmask returned by lookup_classname, or is several such masks bit-or'ed Chris@16: /// together. Chris@16: /// \return true if the character is a member of any of the specified character classes, false Chris@16: /// otherwise. Chris@16: bool isctype(char_type ch, char_class_type mask) const Chris@16: { Chris@16: return this->base_type::is(*this->ctype_, ch, mask); Chris@16: } Chris@16: Chris@16: /// Convert a digit character into the integer it represents. Chris@16: /// Chris@16: /// \param ch The digit character. Chris@16: /// \param radix The radix to use for the conversion. Chris@16: /// \pre radix is one of 8, 10, or 16. Chris@16: /// \return -1 if ch is not a digit character, the integer value of the character otherwise. Chris@16: /// The conversion is performed by imbueing a std::stringstream with this-\>getloc(); Chris@16: /// setting the radix to one of oct, hex or dec; inserting ch into the stream; and Chris@16: /// extracting an int. Chris@16: int value(char_type ch, int radix) const Chris@16: { Chris@16: BOOST_ASSERT(8 == radix || 10 == radix || 16 == radix); Chris@16: int val = -1; Chris@16: std::basic_stringstream str; Chris@16: str.imbue(this->getloc()); Chris@16: str << (8 == radix ? std::oct : (16 == radix ? std::hex : std::dec)); Chris@16: str.put(ch); Chris@16: str >> val; Chris@16: return str.fail() ? -1 : val; Chris@16: } Chris@16: Chris@16: /// Imbues *this with loc Chris@16: /// Chris@16: /// \param loc A std::locale. Chris@16: /// \return the previous std::locale used by *this. Chris@16: locale_type imbue(locale_type loc) Chris@16: { Chris@16: locale_type old_loc = this->loc_; Chris@16: this->loc_ = loc; Chris@16: this->ctype_ = &BOOST_USE_FACET(std::ctype, this->loc_); Chris@16: //this->collate_ = &BOOST_USE_FACET(std::collate, this->loc_); Chris@16: this->base_type::imbue(this->loc_); Chris@16: return old_loc; Chris@16: } Chris@16: Chris@16: /// Returns the current std::locale used by *this. Chris@16: /// Chris@16: locale_type getloc() const Chris@16: { Chris@16: return this->loc_; Chris@16: } Chris@16: Chris@16: private: Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // char_class_pair Chris@16: /// INTERNAL ONLY Chris@16: struct char_class_pair Chris@16: { Chris@16: char_type const *class_name_; Chris@16: char_class_type class_type_; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // char_class Chris@16: /// INTERNAL ONLY Chris@16: static char_class_pair const &char_class(std::size_t j) Chris@16: { Chris@16: static BOOST_CONSTEXPR_OR_CONST char_class_pair s_char_class_map[] = Chris@16: { Chris@16: { BOOST_XPR_CSTR_(char_type, "alnum"), detail::std_ctype_alnum } Chris@16: , { BOOST_XPR_CSTR_(char_type, "alpha"), detail::std_ctype_alpha } Chris@16: , { BOOST_XPR_CSTR_(char_type, "blank"), detail::non_std_ctype_blank } Chris@16: , { BOOST_XPR_CSTR_(char_type, "cntrl"), detail::std_ctype_cntrl } Chris@16: , { BOOST_XPR_CSTR_(char_type, "d"), detail::std_ctype_digit } Chris@16: , { BOOST_XPR_CSTR_(char_type, "digit"), detail::std_ctype_digit } Chris@16: , { BOOST_XPR_CSTR_(char_type, "graph"), detail::std_ctype_graph } Chris@16: , { BOOST_XPR_CSTR_(char_type, "lower"), detail::std_ctype_lower } Chris@16: , { BOOST_XPR_CSTR_(char_type, "newline"),detail::non_std_ctype_newline } Chris@16: , { BOOST_XPR_CSTR_(char_type, "print"), detail::std_ctype_print } Chris@16: , { BOOST_XPR_CSTR_(char_type, "punct"), detail::std_ctype_punct } Chris@16: , { BOOST_XPR_CSTR_(char_type, "s"), detail::std_ctype_space } Chris@16: , { BOOST_XPR_CSTR_(char_type, "space"), detail::std_ctype_space } Chris@16: , { BOOST_XPR_CSTR_(char_type, "upper"), detail::std_ctype_upper } Chris@16: , { BOOST_XPR_CSTR_(char_type, "w"), detail::std_ctype_alnum | detail::non_std_ctype_underscore } Chris@16: , { BOOST_XPR_CSTR_(char_type, "xdigit"), detail::std_ctype_xdigit } Chris@16: , { 0, 0 } Chris@16: }; Chris@16: return s_char_class_map[j]; Chris@16: } Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // lookup_classname_impl Chris@16: /// INTERNAL ONLY Chris@16: template Chris@16: static char_class_type lookup_classname_impl_(FwdIter begin, FwdIter end) Chris@16: { Chris@16: // find the classname Chris@16: typedef cpp_regex_traits this_t; Chris@16: for(std::size_t j = 0; 0 != this_t::char_class(j).class_name_; ++j) Chris@16: { Chris@16: if(this_t::compare_(this_t::char_class(j).class_name_, begin, end)) Chris@16: { Chris@16: return this_t::char_class(j).class_type_; Chris@16: } Chris@16: } Chris@16: return 0; Chris@16: } Chris@16: Chris@16: /// INTERNAL ONLY Chris@16: template Chris@16: static bool compare_(char_type const *name, FwdIter begin, FwdIter end) Chris@16: { Chris@16: for(; *name && begin != end; ++name, ++begin) Chris@16: { Chris@16: if(*name != *begin) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: } Chris@16: return !*name && begin == end; Chris@16: } Chris@16: Chris@16: locale_type loc_; Chris@16: std::ctype const *ctype_; Chris@16: //std::collate const *collate_; Chris@16: }; Chris@16: Chris@16: /////////////////////////////////////////////////////////////////////////////// Chris@16: // cpp_regex_traits<>::hash specializations Chris@16: template<> Chris@16: inline unsigned char cpp_regex_traits::hash(unsigned char ch) Chris@16: { Chris@16: return ch; Chris@16: } Chris@16: Chris@16: template<> Chris@16: inline unsigned char cpp_regex_traits::hash(char ch) Chris@16: { Chris@16: return static_cast(ch); Chris@16: } Chris@16: Chris@16: template<> Chris@16: inline unsigned char cpp_regex_traits::hash(signed char ch) Chris@16: { Chris@16: return static_cast(ch); Chris@16: } Chris@16: Chris@16: #ifndef BOOST_XPRESSIVE_NO_WREGEX Chris@16: template<> Chris@16: inline unsigned char cpp_regex_traits::hash(wchar_t ch) Chris@16: { Chris@16: return static_cast(ch); Chris@16: } Chris@16: #endif Chris@16: Chris@16: // Narrow C++ traits has fold_case() member function. Chris@16: template<> Chris@16: struct has_fold_case > Chris@16: : mpl::true_ Chris@16: { Chris@16: }; Chris@16: Chris@16: Chris@16: }} Chris@16: Chris@16: #endif