Chris@16
|
1 // scan_keyword.hpp --------------------------------------------------------------//
|
Chris@16
|
2 //===----------------------------------------------------------------------===//
|
Chris@16
|
3 //
|
Chris@16
|
4 // The LLVM Compiler Infrastructure
|
Chris@16
|
5 //
|
Chris@16
|
6 // This file is dual licensed under the MIT and the University of Illinois Open
|
Chris@16
|
7 // Source Licenses. See LICENSE.TXT for details.
|
Chris@16
|
8 //
|
Chris@16
|
9 //===----------------------------------------------------------------------===//
|
Chris@16
|
10 // Adaptation to Boost of the libcxx
|
Chris@16
|
11
|
Chris@16
|
12 // Copyright 2010 Vicente J. Botet Escriba
|
Chris@16
|
13
|
Chris@16
|
14 // Distributed under the Boost Software License, Version 1.0.
|
Chris@16
|
15 // See http://www.boost.org/LICENSE_1_0.txt
|
Chris@16
|
16
|
Chris@16
|
17 #ifndef BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP
|
Chris@16
|
18 #define BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/chrono/config.hpp>
|
Chris@16
|
21
|
Chris@101
|
22 #include <boost/move/unique_ptr.hpp>
|
Chris@16
|
23 #include <ios>
|
Chris@16
|
24 #include <exception>
|
Chris@16
|
25 #include <stdlib.h>
|
Chris@16
|
26 #include <boost/throw_exception.hpp>
|
Chris@16
|
27
|
Chris@16
|
28 namespace boost {
|
Chris@101
|
29 using movelib::unique_ptr;
|
Chris@16
|
30
|
Chris@16
|
31 namespace chrono {
|
Chris@16
|
32 namespace chrono_detail {
|
Chris@16
|
33
|
Chris@16
|
34 inline void free_aux(void* ptr) { free(ptr); }
|
Chris@16
|
35
|
Chris@16
|
36 // scan_keyword
|
Chris@16
|
37 // Scans [b, e) until a match is found in the basic_strings range
|
Chris@16
|
38 // [kb, ke) or until it can be shown that there is no match in [kb, ke).
|
Chris@16
|
39 // b will be incremented (visibly), consuming CharT until a match is found
|
Chris@16
|
40 // or proved to not exist. A keyword may be "", in which will match anything.
|
Chris@16
|
41 // If one keyword is a prefix of another, and the next CharT in the input
|
Chris@16
|
42 // might match another keyword, the algorithm will attempt to find the longest
|
Chris@16
|
43 // matching keyword. If the longer matching keyword ends up not matching, then
|
Chris@16
|
44 // no keyword match is found. If no keyword match is found, ke is returned
|
Chris@16
|
45 // and failbit is set in err.
|
Chris@16
|
46 // Else an iterator pointing to the matching keyword is found. If more than
|
Chris@16
|
47 // one keyword matches, an iterator to the first matching keyword is returned.
|
Chris@16
|
48 // If on exit b == e, eofbit is set in err.
|
Chris@16
|
49 // Examples:
|
Chris@16
|
50 // Keywords: "a", "abb"
|
Chris@16
|
51 // If the input is "a", the first keyword matches and eofbit is set.
|
Chris@16
|
52 // If the input is "abc", no match is found and "ab" are consumed.
|
Chris@16
|
53
|
Chris@16
|
54 template <class InputIterator, class ForwardIterator>
|
Chris@16
|
55 ForwardIterator
|
Chris@16
|
56 scan_keyword(InputIterator& b, InputIterator e,
|
Chris@16
|
57 ForwardIterator kb, ForwardIterator ke,
|
Chris@16
|
58 std::ios_base::iostate& err
|
Chris@16
|
59 )
|
Chris@16
|
60 {
|
Chris@16
|
61 typedef typename std::iterator_traits<InputIterator>::value_type CharT;
|
Chris@16
|
62 size_t nkw = std::distance(kb, ke);
|
Chris@16
|
63 const unsigned char doesnt_match = '\0';
|
Chris@16
|
64 const unsigned char might_match = '\1';
|
Chris@16
|
65 const unsigned char does_match = '\2';
|
Chris@16
|
66 unsigned char statbuf[100];
|
Chris@16
|
67 unsigned char* status = statbuf;
|
Chris@16
|
68 // Change free by free_aux to avoid
|
Chris@16
|
69 // Error: Could not find a match for boost::interprocess::unique_ptr<unsigned char, void(*)(void*)>::unique_ptr(int, extern "C" void(void*))
|
Chris@16
|
70 unique_ptr<unsigned char, void(*)(void*)> stat_hold(0, free_aux);
|
Chris@16
|
71 if (nkw > sizeof(statbuf))
|
Chris@16
|
72 {
|
Chris@16
|
73 status = (unsigned char*)malloc(nkw);
|
Chris@16
|
74 if (status == 0)
|
Chris@16
|
75 throw_exception(std::bad_alloc());
|
Chris@16
|
76 stat_hold.reset(status);
|
Chris@16
|
77 }
|
Chris@16
|
78 size_t n_might_match = nkw; // At this point, any keyword might match
|
Chris@16
|
79 size_t n_does_match = 0; // but none of them definitely do
|
Chris@16
|
80 // Initialize all statuses to might_match, except for "" keywords are does_match
|
Chris@16
|
81 unsigned char* st = status;
|
Chris@16
|
82 for (ForwardIterator ky = kb; ky != ke; ++ky, ++st)
|
Chris@16
|
83 {
|
Chris@16
|
84 if (!ky->empty())
|
Chris@16
|
85 *st = might_match;
|
Chris@16
|
86 else
|
Chris@16
|
87 {
|
Chris@16
|
88 *st = does_match;
|
Chris@16
|
89 --n_might_match;
|
Chris@16
|
90 ++n_does_match;
|
Chris@16
|
91 }
|
Chris@16
|
92 }
|
Chris@16
|
93 // While there might be a match, test keywords against the next CharT
|
Chris@16
|
94 for (size_t indx = 0; b != e && n_might_match > 0; ++indx)
|
Chris@16
|
95 {
|
Chris@16
|
96 // Peek at the next CharT but don't consume it
|
Chris@16
|
97 CharT c = *b;
|
Chris@16
|
98 bool consume = false;
|
Chris@16
|
99 // For each keyword which might match, see if the indx character is c
|
Chris@16
|
100 // If a match if found, consume c
|
Chris@16
|
101 // If a match is found, and that is the last character in the keyword,
|
Chris@16
|
102 // then that keyword matches.
|
Chris@16
|
103 // If the keyword doesn't match this character, then change the keyword
|
Chris@16
|
104 // to doesn't match
|
Chris@16
|
105 st = status;
|
Chris@16
|
106 for (ForwardIterator ky = kb; ky != ke; ++ky, ++st)
|
Chris@16
|
107 {
|
Chris@16
|
108 if (*st == might_match)
|
Chris@16
|
109 {
|
Chris@16
|
110 CharT kc = (*ky)[indx];
|
Chris@16
|
111 if (c == kc)
|
Chris@16
|
112 {
|
Chris@16
|
113 consume = true;
|
Chris@16
|
114 if (ky->size() == indx+1)
|
Chris@16
|
115 {
|
Chris@16
|
116 *st = does_match;
|
Chris@16
|
117 --n_might_match;
|
Chris@16
|
118 ++n_does_match;
|
Chris@16
|
119 }
|
Chris@16
|
120 }
|
Chris@16
|
121 else
|
Chris@16
|
122 {
|
Chris@16
|
123 *st = doesnt_match;
|
Chris@16
|
124 --n_might_match;
|
Chris@16
|
125 }
|
Chris@16
|
126 }
|
Chris@16
|
127 }
|
Chris@16
|
128 // consume if we matched a character
|
Chris@16
|
129 if (consume)
|
Chris@16
|
130 {
|
Chris@16
|
131 ++b;
|
Chris@16
|
132 // If we consumed a character and there might be a matched keyword that
|
Chris@16
|
133 // was marked matched on a previous iteration, then such keywords
|
Chris@16
|
134 // which are now marked as not matching.
|
Chris@16
|
135 if (n_might_match + n_does_match > 1)
|
Chris@16
|
136 {
|
Chris@16
|
137 st = status;
|
Chris@16
|
138 for (ForwardIterator ky = kb; ky != ke; ++ky, ++st)
|
Chris@16
|
139 {
|
Chris@16
|
140 if (*st == does_match && ky->size() != indx+1)
|
Chris@16
|
141 {
|
Chris@16
|
142 *st = doesnt_match;
|
Chris@16
|
143 --n_does_match;
|
Chris@16
|
144 }
|
Chris@16
|
145 }
|
Chris@16
|
146 }
|
Chris@16
|
147 }
|
Chris@16
|
148 }
|
Chris@16
|
149 // We've exited the loop because we hit eof and/or we have no more "might matches".
|
Chris@16
|
150 if (b == e)
|
Chris@16
|
151 err |= std::ios_base::eofbit;
|
Chris@16
|
152 // Return the first matching result
|
Chris@16
|
153 for (st = status; kb != ke; ++kb, ++st)
|
Chris@16
|
154 if (*st == does_match)
|
Chris@16
|
155 break;
|
Chris@16
|
156 if (kb == ke)
|
Chris@16
|
157 err |= std::ios_base::failbit;
|
Chris@16
|
158 return kb;
|
Chris@16
|
159 }
|
Chris@16
|
160 }
|
Chris@16
|
161 }
|
Chris@16
|
162 }
|
Chris@16
|
163 #endif // BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP
|