blob: b20ad445acd97dbcadbadd06a0e45c839ed983b5 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu5e974202014-01-29 16:59:06 -08002/**
Alexander Afanasyevc169a812014-05-20 20:37:29 -04003 * Copyright (c) 2013-2014 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu5e974202014-01-29 16:59:06 -080022 */
23
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080024#ifndef NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP
25#define NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP
Yingdi Yu5e974202014-01-29 16:59:06 -080026
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080027#include "../../common.hpp"
Yingdi Yu5e974202014-01-29 16:59:06 -080028
29#include "regex-matcher.hpp"
30#include "regex-component-matcher.hpp"
31
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070032#include <set>
33
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080034namespace ndn {
Yingdi Yu5e974202014-01-29 16:59:06 -080035
Alexander Afanasyev2a7f7202014-04-23 14:25:29 -070036class RegexComponentSetMatcher : public RegexMatcher
37{
Yingdi Yu5e974202014-01-29 16:59:06 -080038public:
39 /**
40 * @brief Create a RegexComponentSetMatcher matcher from expr
41 * @param expr The standard regular expression to match a component
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070042 * @param backrefManager Shared pointer to back-reference manager
Yingdi Yu5e974202014-01-29 16:59:06 -080043 */
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070044 RegexComponentSetMatcher(const std::string& expr, shared_ptr<RegexBackrefManager> backrefManager);
Yingdi Yu5e974202014-01-29 16:59:06 -080045
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070046 virtual
47 ~RegexComponentSetMatcher();
Yingdi Yu5e974202014-01-29 16:59:06 -080048
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070049 virtual bool
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070050 match(const Name& name, size_t offset, size_t len = 1);
Yingdi Yu5e974202014-01-29 16:59:06 -080051
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070052protected:
Yingdi Yu5e974202014-01-29 16:59:06 -080053 /**
54 * @brief Compile the regular expression to generate the more matchers when necessary
55 * @returns true if compiling succeeds
56 */
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070057 virtual void
Yingdi Yu5e974202014-01-29 16:59:06 -080058 compile();
59
60private:
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070061 size_t
62 extractComponent(size_t index);
Yingdi Yu5e974202014-01-29 16:59:06 -080063
64 void
65 compileSingleComponent();
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070066
Yingdi Yu5e974202014-01-29 16:59:06 -080067 void
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070068 compileMultipleComponents(size_t start, size_t lastIndex);
Yingdi Yu5e974202014-01-29 16:59:06 -080069
70private:
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080071 typedef std::set<shared_ptr<RegexComponentMatcher> > ComponentsSet;
72 ComponentsSet m_components;
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070073 bool m_isInclusion;
Yingdi Yu5e974202014-01-29 16:59:06 -080074};
75
Yingdi Yu5e974202014-01-29 16:59:06 -080076
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080077inline
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070078RegexComponentSetMatcher::RegexComponentSetMatcher(const std::string& expr,
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070079 shared_ptr<RegexBackrefManager> backrefManager)
80 : RegexMatcher(expr, EXPR_COMPONENT_SET, backrefManager)
81 , m_isInclusion(true)
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080082{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080083 compile();
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080084}
85
86inline
87RegexComponentSetMatcher::~RegexComponentSetMatcher()
88{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080089}
90
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070091inline void
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080092RegexComponentSetMatcher::compile()
93{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070094 if (m_expr.size() < 2)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -070095 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Regexp compile error (cannot parse " +
96 m_expr + ")"));
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070097
98 switch (m_expr[0]) {
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080099 case '<':
100 return compileSingleComponent();
101 case '[':
102 {
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700103 size_t lastIndex = m_expr.size() - 1;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700104 if (']' != m_expr[lastIndex])
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700105 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Regexp compile error (no matching ']' in " +
106 m_expr + ")"));
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700107
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700108 if ('^' == m_expr[1]) {
109 m_isInclusion = false;
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800110 compileMultipleComponents(2, lastIndex);
111 }
112 else
113 compileMultipleComponents(1, lastIndex);
114 break;
115 }
116 default:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700117 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Regexp compile error (cannot parse " +
118 m_expr + ")"));
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800119 }
120}
121
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700122inline void
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800123RegexComponentSetMatcher::compileSingleComponent()
124{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700125 size_t end = extractComponent(1);
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800126
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700127 if (m_expr.size() != end)
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800128 {
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700129 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Component expr error " + m_expr));
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800130 }
131 else
132 {
133 shared_ptr<RegexComponentMatcher> component =
134 make_shared<RegexComponentMatcher>(m_expr.substr(1, end - 2), m_backrefManager);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700135
136 m_components.insert(component);
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800137 }
138}
139
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700140inline void
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700141RegexComponentSetMatcher::compileMultipleComponents(size_t start, size_t lastIndex)
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800142{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700143 size_t index = start;
144 size_t tempIndex = start;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700145
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700146 while (index < lastIndex) {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700147 if ('<' != m_expr[index])
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700148 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Component expr error " + m_expr));
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700149
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700150 tempIndex = index + 1;
151 index = extractComponent(tempIndex);
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800152
153 shared_ptr<RegexComponentMatcher> component =
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700154 make_shared<RegexComponentMatcher>(m_expr.substr(tempIndex, index - tempIndex - 1),
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700155 m_backrefManager);
156
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800157 m_components.insert(component);
158 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700159
160 if (index != lastIndex)
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700161 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Not sufficient expr to parse " + m_expr));
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800162}
163
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700164inline bool
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700165RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len)
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800166{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700167 bool isMatched = false;
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800168
169 /* componentset only matches one component */
170 if (len != 1)
171 {
172 return false;
173 }
174
175 for (ComponentsSet::iterator it = m_components.begin();
176 it != m_components.end();
177 ++it)
178 {
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700179 if ((*it)->match(name, offset, len))
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800180 {
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700181 isMatched = true;
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800182 break;
183 }
184 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700185
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800186 m_matchResult.clear();
187
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700188 if (m_isInclusion ? isMatched : !isMatched)
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800189 {
190 m_matchResult.push_back(name.get(offset));
191 return true;
192 }
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700193 else
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800194 return false;
195}
196
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700197inline size_t
198RegexComponentSetMatcher::extractComponent(size_t index)
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800199{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700200 size_t lcount = 1;
201 size_t rcount = 0;
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800202
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700203 while (lcount > rcount) {
204 switch (m_expr[index]) {
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800205 case '<':
206 lcount++;
207 break;
208
209 case '>':
210 rcount++;
211 break;
212
213 case 0:
Spyridon Mastorakis0d2ed2e2015-07-27 19:09:12 -0700214 BOOST_THROW_EXCEPTION(RegexMatcher::Error("Error: square brackets mismatch"));
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800215 break;
216 }
217 index++;
218
219 }
220
221 return index;
222}
223
224} // namespace ndn
225
226#endif // NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP