| #ifndef REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 | |
| #define REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 | |
| #if defined(_MSC_VER) || \ | |
| (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ | |
| (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 | |
| #pragma once | |
| #endif | |
| #include "stream.h" | |
| #include "streamcharsource.h" | |
| #include "stringsource.h" | |
| namespace YAML { | |
| // query matches | |
| inline bool RegEx::Matches(char ch) const { | |
| std::string str; | |
| str += ch; | |
| return Matches(str); | |
| } | |
| inline bool RegEx::Matches(const std::string& str) const { | |
| return Match(str) >= 0; | |
| } | |
| inline bool RegEx::Matches(const Stream& in) const { return Match(in) >= 0; } | |
| template <typename Source> | |
| inline bool RegEx::Matches(const Source& source) const { | |
| #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201103L) || __cplusplus >= 201103L) | |
| static_assert(!std::is_same<Source, const char*>::value, | |
| #endif | |
| "Must use StringCharSource instead of plain C-string"); | |
| return Match(source) >= 0; | |
| } | |
| // Match | |
| // . Matches the given string against this regular expression. | |
| // . Returns the number of characters matched. | |
| // . Returns -1 if no characters were matched (the reason for | |
| // not returning zero is that we may have an empty regex | |
| // which is ALWAYS successful at matching zero characters). | |
| // . REMEMBER that we only match from the start of the buffer! | |
| inline int RegEx::Match(const std::string& str) const { | |
| StringCharSource source(str.c_str(), str.size()); | |
| return Match(source); | |
| } | |
| inline int RegEx::Match(const Stream& in) const { | |
| StreamCharSource source(in); | |
| return Match(source); | |
| } | |
| template <typename Source> | |
| inline bool RegEx::IsValidSource(const Source& source) const { | |
| return source; | |
| } | |
| template <> | |
| inline bool RegEx::IsValidSource<StringCharSource>( | |
| const StringCharSource& source) const { | |
| switch (m_op) { | |
| case REGEX_MATCH: | |
| case REGEX_RANGE: | |
| return source; | |
| default: | |
| return true; | |
| } | |
| } | |
| template <typename Source> | |
| inline int RegEx::Match(const Source& source) const { | |
| return IsValidSource(source) ? MatchUnchecked(source) : -1; | |
| } | |
| template <typename Source> | |
| inline int RegEx::MatchUnchecked(const Source& source) const { | |
| switch (m_op) { | |
| case REGEX_EMPTY: | |
| return MatchOpEmpty(source); | |
| case REGEX_MATCH: | |
| return MatchOpMatch(source); | |
| case REGEX_RANGE: | |
| return MatchOpRange(source); | |
| case REGEX_OR: | |
| return MatchOpOr(source); | |
| case REGEX_AND: | |
| return MatchOpAnd(source); | |
| case REGEX_NOT: | |
| return MatchOpNot(source); | |
| case REGEX_SEQ: | |
| return MatchOpSeq(source); | |
| } | |
| return -1; | |
| } | |
| ////////////////////////////////////////////////////////////////////////////// | |
| // Operators | |
| // Note: the convention MatchOp*<Source> is that we can assume | |
| // IsSourceValid(source). | |
| // So we do all our checks *before* we call these functions | |
| // EmptyOperator | |
| template <typename Source> | |
| inline int RegEx::MatchOpEmpty(const Source& source) const { | |
| return source[0] == Stream::eof() ? 0 : -1; | |
| } | |
| template <> | |
| inline int RegEx::MatchOpEmpty<StringCharSource>( | |
| const StringCharSource& source) const { | |
| return !source ? 0 : -1; // the empty regex only is successful on the empty | |
| // string | |
| } | |
| // MatchOperator | |
| template <typename Source> | |
| inline int RegEx::MatchOpMatch(const Source& source) const { | |
| if (source[0] != m_a) | |
| return -1; | |
| return 1; | |
| } | |
| // RangeOperator | |
| template <typename Source> | |
| inline int RegEx::MatchOpRange(const Source& source) const { | |
| if (m_a > source[0] || m_z < source[0]) | |
| return -1; | |
| return 1; | |
| } | |
| // OrOperator | |
| template <typename Source> | |
| inline int RegEx::MatchOpOr(const Source& source) const { | |
| for (const RegEx& param : m_params) { | |
| int n = param.MatchUnchecked(source); | |
| if (n >= 0) | |
| return n; | |
| } | |
| return -1; | |
| } | |
| // AndOperator | |
| // Note: 'AND' is a little funny, since we may be required to match things | |
| // of different lengths. If we find a match, we return the length of | |
| // the FIRST entry on the list. | |
| template <typename Source> | |
| inline int RegEx::MatchOpAnd(const Source& source) const { | |
| int first = -1; | |
| for (std::size_t i = 0; i < m_params.size(); i++) { | |
| int n = m_params[i].MatchUnchecked(source); | |
| if (n == -1) | |
| return -1; | |
| if (i == 0) | |
| first = n; | |
| } | |
| return first; | |
| } | |
| // NotOperator | |
| template <typename Source> | |
| inline int RegEx::MatchOpNot(const Source& source) const { | |
| if (m_params.empty()) | |
| return -1; | |
| if (m_params[0].MatchUnchecked(source) >= 0) | |
| return -1; | |
| return 1; | |
| } | |
| // SeqOperator | |
| template <typename Source> | |
| inline int RegEx::MatchOpSeq(const Source& source) const { | |
| int offset = 0; | |
| for (const RegEx& param : m_params) { | |
| int n = param.Match(source + offset); // note Match, not | |
| // MatchUnchecked because we | |
| // need to check validity after | |
| // the offset | |
| if (n == -1) | |
| return -1; | |
| offset += n; | |
| } | |
| return offset; | |
| } | |
| } // namespace YAML | |
| #endif // REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 |