/////////////////////////////////////////////////////////////////////////////// | |
// hash_peek_bitset.hpp | |
// | |
// 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_DETAIL_HASH_PEEK_BITSET_HPP_EAN_10_04_2005 | |
#define BOOST_XPRESSIVE_DETAIL_HASH_PEEK_BITSET_HPP_EAN_10_04_2005 | |
// MS compatible compilers support #pragma once | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma once | |
# pragma warning(push) | |
# pragma warning(disable : 4100) // unreferenced formal parameter | |
# pragma warning(disable : 4127) // conditional expression constant | |
#endif | |
#include <bitset> | |
#include <string> // for std::char_traits | |
#include <boost/xpressive/detail/utility/chset/basic_chset.ipp> | |
namespace boost { namespace xpressive { namespace detail | |
{ | |
/////////////////////////////////////////////////////////////////////////////// | |
// hash_peek_bitset | |
// | |
template<typename Char> | |
struct hash_peek_bitset | |
{ | |
typedef Char char_type; | |
typedef typename std::char_traits<char_type>::int_type int_type; | |
hash_peek_bitset() | |
: icase_(false) | |
, bset_() | |
{ | |
} | |
std::size_t count() const | |
{ | |
return this->bset_.count(); | |
} | |
void set_all() | |
{ | |
this->icase_ = false; | |
this->bset_.set(); | |
} | |
template<typename Traits> | |
void set_char(char_type ch, bool icase, Traits const &tr) | |
{ | |
if(this->test_icase_(icase)) | |
{ | |
ch = icase ? tr.translate_nocase(ch) : tr.translate(ch); | |
this->bset_.set(tr.hash(ch)); | |
} | |
} | |
template<typename Traits> | |
void set_range(char_type from, char_type to, bool no, bool icase, Traits const &tr) | |
{ | |
int_type ifrom = std::char_traits<char_type>::to_int_type(from); | |
int_type ito = std::char_traits<char_type>::to_int_type(to); | |
BOOST_ASSERT(ifrom <= ito); | |
// bound the computational complexity. BUGBUG could set the inverse range | |
if(no || 256 < (ito - ifrom)) | |
{ | |
this->set_all(); | |
} | |
else if(this->test_icase_(icase)) | |
{ | |
for(int_type i = ifrom; i <= ito; ++i) | |
{ | |
char_type ch = std::char_traits<char_type>::to_char_type(i); | |
ch = icase ? tr.translate_nocase(ch) : tr.translate(ch); | |
this->bset_.set(tr.hash(ch)); | |
} | |
} | |
} | |
template<typename Traits> | |
void set_class(typename Traits::char_class_type char_class, bool no, Traits const &tr) | |
{ | |
if(1 != sizeof(char_type)) | |
{ | |
// wide character set, no efficient way of filling in the bitset, so set them all to 1 | |
this->set_all(); | |
} | |
else | |
{ | |
for(std::size_t i = 0; i <= UCHAR_MAX; ++i) | |
{ | |
char_type ch = std::char_traits<char_type>::to_char_type(static_cast<int_type>(i)); | |
if(no != tr.isctype(ch, char_class)) | |
{ | |
this->bset_.set(i); | |
} | |
} | |
} | |
} | |
void set_bitset(hash_peek_bitset<Char> const &that) | |
{ | |
if(this->test_icase_(that.icase())) | |
{ | |
this->bset_ |= that.bset_; | |
} | |
} | |
void set_charset(basic_chset_8bit<Char> const &that, bool icase) | |
{ | |
if(this->test_icase_(icase)) | |
{ | |
this->bset_ |= that.base(); | |
} | |
} | |
bool icase() const | |
{ | |
return this->icase_; | |
} | |
template<typename Traits> | |
bool test(char_type ch, Traits const &tr) const | |
{ | |
ch = this->icase_ ? tr.translate_nocase(ch) : tr.translate(ch); | |
return this->bset_.test(tr.hash(ch)); | |
} | |
template<typename Traits> | |
bool test(char_type ch, Traits const &tr, mpl::false_) const | |
{ | |
BOOST_ASSERT(!this->icase_); | |
return this->bset_.test(tr.hash(tr.translate(ch))); | |
} | |
template<typename Traits> | |
bool test(char_type ch, Traits const &tr, mpl::true_) const | |
{ | |
BOOST_ASSERT(this->icase_); | |
return this->bset_.test(tr.hash(tr.translate_nocase(ch))); | |
} | |
private: | |
// Make sure all sub-expressions being merged have the same case-sensitivity | |
bool test_icase_(bool icase) | |
{ | |
std::size_t count = this->bset_.count(); | |
if(256 == count) | |
{ | |
return false; // all set already, nothing to do | |
} | |
else if(0 != count && this->icase_ != icase) | |
{ | |
this->set_all(); // icase mismatch! set all and bail | |
return false; | |
} | |
this->icase_ = icase; | |
return true; | |
} | |
bool icase_; | |
std::bitset<256> bset_; | |
}; | |
}}} // namespace boost::xpressive::detail | |
#if defined(_MSC_VER) && (_MSC_VER >= 1020) | |
# pragma warning(pop) | |
#endif | |
#endif |