scan_keyword.hpp 5.9 KB

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