164 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			164 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| //  scan_keyword.hpp  --------------------------------------------------------------//
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is dual licensed under the MIT and the University of Illinois Open
 | |
| // Source Licenses. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //  Adaptation to Boost of the libcxx
 | |
| 
 | |
| //  Copyright 2010 Vicente J. Botet Escriba
 | |
| 
 | |
| //  Distributed under the Boost Software License, Version 1.0.
 | |
| //  See http://www.boost.org/LICENSE_1_0.txt
 | |
| 
 | |
| #ifndef BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP
 | |
| #define BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP
 | |
| 
 | |
| #include <boost/chrono/config.hpp>
 | |
| 
 | |
| #include <boost/move/unique_ptr.hpp>
 | |
| #include <ios>
 | |
| #include <exception>
 | |
| #include <stdlib.h>
 | |
| #include <boost/throw_exception.hpp>
 | |
| 
 | |
| namespace boost {
 | |
|     using movelib::unique_ptr;
 | |
| 
 | |
| namespace chrono {
 | |
| namespace chrono_detail {
 | |
| 
 | |
| inline void free_aux(void* ptr) { free(ptr); }
 | |
| 
 | |
| // scan_keyword
 | |
| // Scans [b, e) until a match is found in the basic_strings range
 | |
| //  [kb, ke) or until it can be shown that there is no match in [kb, ke).
 | |
| //  b will be incremented (visibly), consuming CharT until a match is found
 | |
| //  or proved to not exist.  A keyword may be "", in which will match anything.
 | |
| //  If one keyword is a prefix of another, and the next CharT in the input
 | |
| //  might match another keyword, the algorithm will attempt to find the longest
 | |
| //  matching keyword.  If the longer matching keyword ends up not matching, then
 | |
| //  no keyword match is found.  If no keyword match is found, ke is returned
 | |
| //  and failbit is set in err.
 | |
| //  Else an iterator pointing to the matching keyword is found.  If more than
 | |
| //  one keyword matches, an iterator to the first matching keyword is returned.
 | |
| //  If on exit b == e, eofbit is set in err.
 | |
| //  Examples:
 | |
| //  Keywords:  "a", "abb"
 | |
| //  If the input is "a", the first keyword matches and eofbit is set.
 | |
| //  If the input is "abc", no match is found and "ab" are consumed.
 | |
| 
 | |
| template <class InputIterator, class ForwardIterator>
 | |
| ForwardIterator
 | |
| scan_keyword(InputIterator& b, InputIterator e,
 | |
|                ForwardIterator kb, ForwardIterator ke,
 | |
|                std::ios_base::iostate& err
 | |
|                )
 | |
| {
 | |
|     typedef typename std::iterator_traits<InputIterator>::value_type CharT;
 | |
|     size_t nkw = std::distance(kb, ke);
 | |
|     const unsigned char doesnt_match = '\0';
 | |
|     const unsigned char might_match = '\1';
 | |
|     const unsigned char does_match = '\2';
 | |
|     unsigned char statbuf[100];
 | |
|     unsigned char* status = statbuf;
 | |
|     //  Change free by free_aux to avoid
 | |
|     // Error: Could not find a match for boost::interprocess::unique_ptr<unsigned char, void(*)(void*)>::unique_ptr(int, extern "C" void(void*))
 | |
|     unique_ptr<unsigned char, void(*)(void*)> stat_hold(0, free_aux);
 | |
|     if (nkw > sizeof(statbuf))
 | |
|     {
 | |
|         status = (unsigned char*)malloc(nkw);
 | |
|         if (status == 0)
 | |
|           throw_exception(std::bad_alloc());
 | |
|         stat_hold.reset(status);
 | |
|     }
 | |
|     size_t n_might_match = nkw;  // At this point, any keyword might match
 | |
|     size_t n_does_match = 0;       // but none of them definitely do
 | |
|     // Initialize all statuses to might_match, except for "" keywords are does_match
 | |
|     unsigned char* st = status;
 | |
|     for (ForwardIterator ky = kb; ky != ke; ++ky, ++st)
 | |
|     {
 | |
|         if (!ky->empty())
 | |
|             *st = might_match;
 | |
|         else
 | |
|         {
 | |
|             *st = does_match;
 | |
|             --n_might_match;
 | |
|             ++n_does_match;
 | |
|         }
 | |
|     }
 | |
|     // While there might be a match, test keywords against the next CharT
 | |
|     for (size_t indx = 0; b != e && n_might_match > 0; ++indx)
 | |
|     {
 | |
|         // Peek at the next CharT but don't consume it
 | |
|         CharT c = *b;
 | |
|         bool consume = false;
 | |
|         // For each keyword which might match, see if the indx character is c
 | |
|         // If a match if found, consume c
 | |
|         // If a match is found, and that is the last character in the keyword,
 | |
|         //    then that keyword matches.
 | |
|         // If the keyword doesn't match this character, then change the keyword
 | |
|         //    to doesn't match
 | |
|         st = status;
 | |
|         for (ForwardIterator ky = kb; ky != ke; ++ky, ++st)
 | |
|         {
 | |
|             if (*st == might_match)
 | |
|             {
 | |
|                 CharT kc = (*ky)[indx];
 | |
|                 if (c == kc)
 | |
|                 {
 | |
|                     consume = true;
 | |
|                     if (ky->size() == indx+1)
 | |
|                     {
 | |
|                         *st = does_match;
 | |
|                         --n_might_match;
 | |
|                         ++n_does_match;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     *st = doesnt_match;
 | |
|                     --n_might_match;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         // consume if we matched a character
 | |
|         if (consume)
 | |
|         {
 | |
|             ++b;
 | |
|             // If we consumed a character and there might be a matched keyword that
 | |
|             //   was marked matched on a previous iteration, then such keywords
 | |
|             //   which are now marked as not matching.
 | |
|             if (n_might_match + n_does_match > 1)
 | |
|             {
 | |
|                 st = status;
 | |
|                 for (ForwardIterator ky = kb; ky != ke; ++ky, ++st)
 | |
|                 {
 | |
|                     if (*st == does_match && ky->size() != indx+1)
 | |
|                     {
 | |
|                         *st = doesnt_match;
 | |
|                         --n_does_match;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     // We've exited the loop because we hit eof and/or we have no more "might matches".
 | |
|     if (b == e)
 | |
|         err |= std::ios_base::eofbit;
 | |
|     // Return the first matching result
 | |
|     for (st = status; kb != ke; ++kb, ++st)
 | |
|         if (*st == does_match)
 | |
|             break;
 | |
|     if (kb == ke)
 | |
|         err |= std::ios_base::failbit;
 | |
|     return kb;
 | |
| }
 | |
| }
 | |
| }
 | |
| }
 | |
| #endif // BOOST_CHRONO_DETAIL_SCAN_KEYWORD_HPP
 | 
