1 ///////////////////////////////////////////////////////////////////////////////
2 // hash_peek_bitset.hpp
3 //
4 //  Copyright 2008 Eric Niebler. Distributed under the Boost
5 //  Software License, Version 1.0. (See accompanying file
6 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 #ifndef BOOST_XPRESSIVE_DETAIL_HASH_PEEK_BITSET_HPP_EAN_10_04_2005
9 #define BOOST_XPRESSIVE_DETAIL_HASH_PEEK_BITSET_HPP_EAN_10_04_2005
10 
11 // MS compatible compilers support #pragma once
12 #if defined(_MSC_VER)
13 # pragma once
14 # pragma warning(push)
15 # pragma warning(disable : 4100) // unreferenced formal parameter
16 # pragma warning(disable : 4127) // conditional expression constant
17 #endif
18 
19 #include <bitset>
20 #include <string> // for std::char_traits
21 #include <boost/xpressive/detail/utility/chset/basic_chset.ipp>
22 
23 namespace boost { namespace xpressive { namespace detail
24 {
25 
26 ///////////////////////////////////////////////////////////////////////////////
27 // hash_peek_bitset
28 //
29 template<typename Char>
30 struct hash_peek_bitset
31 {
32     typedef Char char_type;
33     typedef typename std::char_traits<char_type>::int_type int_type;
34 
hash_peek_bitsetboost::xpressive::detail::hash_peek_bitset35     hash_peek_bitset()
36       : icase_(false)
37       , bset_()
38     {
39     }
40 
countboost::xpressive::detail::hash_peek_bitset41     std::size_t count() const
42     {
43         return this->bset_.count();
44     }
45 
set_allboost::xpressive::detail::hash_peek_bitset46     void set_all()
47     {
48         this->icase_ = false;
49         this->bset_.set();
50     }
51 
52     template<typename Traits>
set_charboost::xpressive::detail::hash_peek_bitset53     void set_char(char_type ch, bool icase, Traits const &tr)
54     {
55         if(this->test_icase_(icase))
56         {
57             ch = icase ? tr.translate_nocase(ch) : tr.translate(ch);
58             this->bset_.set(tr.hash(ch));
59         }
60     }
61 
62     template<typename Traits>
set_rangeboost::xpressive::detail::hash_peek_bitset63     void set_range(char_type from, char_type to, bool no, bool icase, Traits const &tr)
64     {
65         int_type ifrom = std::char_traits<char_type>::to_int_type(from);
66         int_type ito = std::char_traits<char_type>::to_int_type(to);
67         BOOST_ASSERT(ifrom <= ito);
68         // bound the computational complexity. BUGBUG could set the inverse range
69         if(no || 256 < (ito - ifrom))
70         {
71             this->set_all();
72         }
73         else if(this->test_icase_(icase))
74         {
75             for(int_type i = ifrom; i <= ito; ++i)
76             {
77                 char_type ch = std::char_traits<char_type>::to_char_type(i);
78                 ch = icase ? tr.translate_nocase(ch) : tr.translate(ch);
79                 this->bset_.set(tr.hash(ch));
80             }
81         }
82     }
83 
84     template<typename Traits>
set_classboost::xpressive::detail::hash_peek_bitset85     void set_class(typename Traits::char_class_type char_class, bool no, Traits const &tr)
86     {
87         if(1 != sizeof(char_type))
88         {
89             // wide character set, no efficient way of filling in the bitset, so set them all to 1
90             this->set_all();
91         }
92         else
93         {
94             for(std::size_t i = 0; i <= UCHAR_MAX; ++i)
95             {
96                 char_type ch = std::char_traits<char_type>::to_char_type(static_cast<int_type>(i));
97                 if(no != tr.isctype(ch, char_class))
98                 {
99                     this->bset_.set(i);
100                 }
101             }
102         }
103     }
104 
set_bitsetboost::xpressive::detail::hash_peek_bitset105     void set_bitset(hash_peek_bitset<Char> const &that)
106     {
107         if(this->test_icase_(that.icase()))
108         {
109             this->bset_ |= that.bset_;
110         }
111     }
112 
set_charsetboost::xpressive::detail::hash_peek_bitset113     void set_charset(basic_chset_8bit<Char> const &that, bool icase)
114     {
115         if(this->test_icase_(icase))
116         {
117             this->bset_ |= that.base();
118         }
119     }
120 
icaseboost::xpressive::detail::hash_peek_bitset121     bool icase() const
122     {
123         return this->icase_;
124     }
125 
126     template<typename Traits>
testboost::xpressive::detail::hash_peek_bitset127     bool test(char_type ch, Traits const &tr) const
128     {
129         ch = this->icase_ ? tr.translate_nocase(ch) : tr.translate(ch);
130         return this->bset_.test(tr.hash(ch));
131     }
132 
133     template<typename Traits>
testboost::xpressive::detail::hash_peek_bitset134     bool test(char_type ch, Traits const &tr, mpl::false_) const
135     {
136         BOOST_ASSERT(!this->icase_);
137         return this->bset_.test(tr.hash(tr.translate(ch)));
138     }
139 
140     template<typename Traits>
testboost::xpressive::detail::hash_peek_bitset141     bool test(char_type ch, Traits const &tr, mpl::true_) const
142     {
143         BOOST_ASSERT(this->icase_);
144         return this->bset_.test(tr.hash(tr.translate_nocase(ch)));
145     }
146 
147 private:
148 
149     // Make sure all sub-expressions being merged have the same case-sensitivity
test_icase_boost::xpressive::detail::hash_peek_bitset150     bool test_icase_(bool icase)
151     {
152         std::size_t count = this->bset_.count();
153 
154         if(256 == count)
155         {
156             return false; // all set already, nothing to do
157         }
158         else if(0 != count && this->icase_ != icase)
159         {
160             this->set_all(); // icase mismatch! set all and bail
161             return false;
162         }
163 
164         this->icase_ = icase;
165         return true;
166     }
167 
168     bool icase_;
169     std::bitset<256> bset_;
170 };
171 
172 }}} // namespace boost::xpressive::detail
173 
174 #if defined(_MSC_VER)
175 # pragma warning(pop)
176 #endif
177 
178 #endif
179