RSB  0.7.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Scope.cpp
Go to the documentation of this file.
1 /* ============================================================
2  *
3  * This file is a part of the RSB project.
4  *
5  * Copyright (C) 2011 by Johannes Wienke <jwienke at techfak dot uni-bielefeld dot de>
6  *
7  * This file may be licensed under the terms of the
8  * GNU Lesser General Public License Version 3 (the ``LGPL''),
9  * or (at your option) any later version.
10  *
11  * Software distributed under the License is distributed
12  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
13  * express or implied. See the LGPL for the specific language
14  * governing rights and limitations.
15  *
16  * You should have received a copy of the LGPL along with this
17  * program. If not, go to http://www.gnu.org/licenses/lgpl.html
18  * or write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  * The development of this software was supported by:
22  * CoR-Lab, Research Institute for Cognition and Robotics
23  * Bielefeld University
24  *
25  * ============================================================ */
26 
27 #include "Scope.h"
28 
29 #include <sstream>
30 #include <stdexcept>
31 #include <iterator>
32 
33 #include <boost/format.hpp>
34 
35 using namespace std;
36 
37 using namespace boost;
38 
39 namespace rsb {
40 
41 const char Scope::COMPONENT_SEPARATOR = '/';
42 
53 inline void verifyAndSplit(const string& s, vector<string>& components,
54  string& normalizedString) {
55  if (s.empty()) {
56  throw invalid_argument("Empty scope string given.");
57  }
58  string::const_iterator prev = s.begin();
59  // The scope string has to start with a '/'.
60  if (*prev != Scope::COMPONENT_SEPARATOR) {
61  throw invalid_argument(
62  str(
63  format(
64  "Invalid scope syntax for '%1%': has to begin with '%2%'")
65  % s % Scope::COMPONENT_SEPARATOR));
66  }
67 
68  // Process remainder of s. If we are at the end of s already, it
69  // denotes the root scope and we do not have to create any
70  // components.
71  string::const_iterator next = prev + 1;
72  for (; next != s.end(); ++next) {
73  // If we encounter a '/', make sure that we accumulated at
74  // least one character in the current scope component.
75  if (*next == Scope::COMPONENT_SEPARATOR) {
76  if (distance(prev, next) == 1) {
77  throw invalid_argument(
78  str(
79  format(
80  "Invalid scope syntax for '%1%' at char %2%: zero-length component between two '%3%'")
81  % s % distance(s.begin(), next)
82  % Scope::COMPONENT_SEPARATOR));
83  }
84  components.push_back(string(prev + 1, next));
85  prev = next;
86  }
87  // The current character is not a '/' and we want to append it
88  // to the current scope component. Verify that it is a legal
89  // scope component character.
90  else if (!(('a' <= *next && *next <= 'z')
91  || ('A' <= *next && *next <= 'Z')
92  || ('0' <= *next && *next <= '9'))) {
93  throw invalid_argument(
94  str(
95  format(
96  "Invalid scope syntax for '%1%' at char %2%: invalid character '%3%'")
97  % s % distance(s.begin(), next) % *next));
98  }
99  // The current character is a valid scope component
100  // character. Append it to the current scope component.
101  }
102  if (prev + 1 != next) {
103  components.push_back(string(prev + 1, next));
104  }
105 
106  // now build the normalized string. ATM we only need to check for the
107  // trailing slash, All other things are handled by the checks before
108  normalizedString = s;
109  if (*(--s.end()) != Scope::COMPONENT_SEPARATOR) {
110  normalizedString += Scope::COMPONENT_SEPARATOR;
111  }
112 
113 }
114 
115 Scope::Scope(const string& s) :
116  scopestring() {
117  // reserve a number of vector components that should be enough for most
118  // realistic scopes. This speeds up parsing.
119  components.reserve(10);
120  verifyAndSplit(s, this->components, this->scopestring);
121 }
122 
123 Scope::Scope(const char *scope) :
124  scopestring() {
125  // reserve a number of vector components that should be enough for most
126  // realistic scopes. This speeds up parsing.
127  components.reserve(10);
128  verifyAndSplit(string(scope), this->components, this->scopestring);
129 }
130 
132  scopestring("/") {
133 }
134 
136 }
137 
138 const vector<string>& Scope::getComponents() const {
139  return components;
140 }
141 
142 const std::string& Scope::toString() const {
143  return this->scopestring;
144 }
145 
146 Scope Scope::concat(const Scope& childScope) const {
147  Scope result; // start with empty string cache
148  result.components = this->components;
149 
150  for (vector<string>::const_iterator it = childScope.components.begin();
151  it != childScope.components.end(); ++it) {
152  result.components.push_back(*it);
153  }
154  result.updateStringCache();
155 
156  return result;
157 }
158 
159 bool Scope::isSubScopeOf(const Scope& other) const {
160 
161  if (components.size() <= other.components.size()) {
162  return false;
163  }
164 
165  for (size_t i = 0; i < other.components.size(); ++i) {
166  if (components[i] != other.components[i]) {
167  return false;
168  }
169  }
170 
171  return true;
172 }
173 
174 bool Scope::isSuperScopeOf(const Scope& other) const {
175 
176  if (components.size() >= other.components.size()) {
177  return false;
178  }
179 
180  for (size_t i = 0; i < components.size(); ++i) {
181  if (components[i] != other.components[i]) {
182  return false;
183  }
184  }
185 
186  return true;
187 }
188 
190  unsigned int scopesize = 1;
191  for (vector<string>::const_iterator it = components.begin();
192  it != components.end(); ++it) {
193  scopesize += it->size() + 1;
194  }
195 
196  this->scopestring.resize(scopesize);
197  this->scopestring[0] = COMPONENT_SEPARATOR;
198  string::iterator cursor = scopestring.begin() + 1;
199  for (vector<string>::const_iterator it = components.begin();
200  it != components.end(); ++it) {
201  std::copy(it->begin(), it->end(), cursor);
202  cursor += it->size();
203  *cursor++ = COMPONENT_SEPARATOR;
204  }
205 }
206 
207 vector<Scope> Scope::superScopes(const bool& includeSelf) const {
208 
209  vector<Scope> result;
210 
211  if (!components.empty()) {
212 
213  // this math only works for scopes that are not the root scope
214  for (size_t requiredComponents = 0;
215  requiredComponents <= components.size() - 1;
216  ++requiredComponents) {
217 
218  Scope super;
219  for (size_t i = 0; i < requiredComponents; ++i) {
220  super.components.push_back(components[i]);
221  }
222  super.updateStringCache();
223  result.push_back(super);
224 
225  }
226 
227  }
228 
229  if (includeSelf) {
230  result.push_back(*this);
231  }
232 
233  return result;
234 }
235 
236 bool Scope::operator==(const Scope& other) const {
237  return toString() == other.toString();
238 }
239 
240 bool Scope::operator<(const Scope& other) const {
241  return toString() < other.toString();
242 }
243 
244 ostream& operator<<(ostream& stream, const Scope& scope) {
245  return stream << "Scope[" << scope.toString() << "]";
246 }
247 
248 }