NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
tgTags.h
Go to the documentation of this file.
1 /*
2  * Copyright © 2012, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The NASA Tensegrity Robotics Toolkit (NTRT) v1 platform is licensed
7  * under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * http://www.apache.org/licenses/LICENSE-2.0.
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
15  * either express or implied. See the License for the specific language
16  * governing permissions and limitations under the License.
17 */
18 
26 #ifndef TG_TAGS_H
27 #define TG_TAGS_H
28 
29 #include <deque>
30 #include <set>
31 #include <string>
32 #include <algorithm>
33 #include <iostream>
34 #include <sstream>
35 #include <locale> // std::locale, std::isalnum
36 
37 #include "tgException.h"
38 
39 struct tgTagException : public tgException
40 {
41  tgTagException(std::string ss) : tgException(ss) {}
42 };
43 
44 class tgTags
45 {
46 public:
47  tgTags() {}
48  tgTags(const std::string& space_separated_tags)
49  {
50  append(space_separated_tags);
51  }
52 
53  bool contains(const std::string& space_separated_tags) const
54  {
55  const std::deque<std::string> tags = splitTags(space_separated_tags);
56  return contains(tags);
57  }
58 
59  bool contains(const tgTags& tags) const
60  {
61  return contains(tags.getTags());
62  }
63 
64  bool containsAny(const std::string& space_separated_tags)
65  {
66  std::deque<std::string> tags = splitTags(space_separated_tags);
67  return containsAny(tags);
68  }
69 
70  bool containsAny(const tgTags& tags)
71  {
72  return containsAny(tags.getTags());
73  }
74 
75  void append(const std::string& space_separated_tags)
76  {
77  append(splitTags(space_separated_tags));
78  }
79 
80  void append(const tgTags& tags)
81  {
82  append(tags.getTags());
83  }
84 
85  void prepend(const std::string& space_separated_tags)
86  {
87  prepend(splitTags(space_separated_tags));
88  }
89 
90  void prepend(const tgTags& tags)
91  {
92  prepend(tags.getTags());
93  }
94 
95  void remove(const std::string& space_separated_tags)
96  {
97  remove(splitTags(space_separated_tags));
98  }
99 
100  void remove(const tgTags& tags)
101  {
102  remove(tags.getTags());
103  }
104 
105  const int size() const
106  {
107  return m_tags.size();
108  }
109 
110  const bool empty() const
111  {
112  return m_tags.empty();
113  }
114 
115  static std::deque<std::string> splitTags(const std::string &s, char delim = ' ') {
116  std::deque<std::string> elems;
117  std::stringstream ss(s);
118  std::string item;
119  while (std::getline(ss, item, delim)) {
120  if(!item.empty())
121  elems.push_back(item);
122  }
123  return elems;
124  }
125 
130  static std::deque<std::string> splitTags(const std::deque<std::string> &s,
131  char delim = ' ') {
132  std::deque<std::string> result;
133  for(std::size_t i = 0; i < s.size(); i++) {
134  std::deque<std::string> spl = splitTags(s[i]);
135  for(std::size_t j = 0; j < spl.size(); j++) {
136  result.push_back(spl[j]);
137  }
138  }
139  return result;
140  }
141 
142  std::string joinTags(std::string delim = "_") {
143  std::stringstream ss;
144  for(std::size_t i = 0; i < m_tags.size(); i++) {
145  if(i != 0) {
146  ss << delim;
147  }
148  ss << m_tags[i];
149  }
150  return ss.str();
151  }
152 
156  bool isIntegery(const std::string s) const
157  {
158  if(s.empty()) {
159  return false;
160  }
161  std::stringstream ss;
162  ss << atoi(s.c_str()); //add number to the stream
163  // If our initial string equals the string converted to int and back to string, it's integery.
164  if(ss.str() == s)
165  return true;
166  return false;
167  }
168 
169  bool isValid(std::string tag)
170  {
171  if (tag.empty())
172  return false;
173 
174  // Can't be an integer
175  if(isIntegery(tag)) {
176  return false;
177  }
178  // Can't contain the delimiter (space)
179  if(tag.find(' ') != std::string::npos) {
180  return false;
181  }
182  // Must be alphanumeric, or at least can't start with strange characters or contain things like '|'
183  // @todo: Add this functionality. Apparently it's not as straightforward as one might hope...
184  //if(!std::isalnum(tag)) {
185  // return false;
186  //}
187  return true;
188  }
189 
190  std::deque<std::string>& getTags()
191  {
192  return m_tags;
193  }
194 
195  const std::deque<std::string>& getTags() const
196  {
197  return m_tags;
198  }
199 
203  const std::set<std::string> asSet() const
204  {
205  return std::set<std::string>(m_tags.begin(), m_tags.end());
206  }
207 
214  std::string& operator[](int key) {
215  return m_tags[key];
216  }
217 
218  const std::string& operator[](int key) const {
219  return m_tags[key];
220  }
221 
225  bool operator==(const tgTags& rhs)
226  {
227  return rhs.asSet() == asSet();
228  }
229 
230  tgTags& operator+=(const tgTags& rhs)
231  {
232  const std::deque<std::string>& other = rhs.getTags();
233  m_tags.insert(m_tags.end(), other.begin(), other.end());
234  return *this;
235  }
236 
237 private:
238 
243  void appendOne(std::string tag) {
244  if(!isValid(tag)) {
245  throw tgTagException("Invalid tag '" + tag + "' - tags must be alphanumeric and may not be castable to int.");
246  }
247  if(!containsOne(tag)) {
248  m_tags.push_back(tag);
249  }
250  }
251 
252  void append(const std::deque<std::string>& tags)
253  {
254  for(std::size_t i = 0; i < tags.size(); i++) {
255  appendOne(tags[i]);
256  }
257  }
258 
259  void prependOne(std::string tag) {
260  if(isValid(tag) && !containsOne(tag)) {
261  m_tags.push_front(tag);
262  }
263  }
264 
265  void prepend(const std::deque<std::string>& tags)
266  {
267  for(std::size_t i = 0; i < tags.size(); i++) {
268  prependOne(tags[i]);
269  }
270  }
271 
272  bool contains(const std::deque<std::string>& tags) const {
273  for(std::size_t i = 0; i < tags.size(); i++) {
274  if(!containsOne(tags[i]))
275  return false;
276  }
277  return true;
278  }
279 
280  bool containsAny(const std::deque<std::string>& tags) const {
281  for(std::size_t i = 0; i < tags.size(); i++) {
282  if(containsOne(tags[i]))
283  return true;
284  }
285  return false;
286  }
287 
291  bool containsOne(std::string tag) const {
292  return (std::find(m_tags.begin(), m_tags.end(), tag) != m_tags.end());
293  }
294 
295  void removeOne(std::string tag) {
296  m_tags.erase(std::remove(m_tags.begin(), m_tags.end(), tag), m_tags.end());
297  }
298 
299  void remove(std::deque<std::string> tags) {
300  for(std::size_t i = 0; i < tags.size(); i++) {
301  removeOne(tags[i]);
302  }
303  }
304 
305  std::deque<std::string> m_tags;
306 };
307 
315 inline std::ostream&
316 operator<<(std::ostream& os, const tgTags& tags)
317 {
318  const std::deque<std::string>& t = tags.getTags();
319  for(size_t i = 0; i < t.size(); ++i)
320  {
321  if(i != 0)
322  os << " ";
323  os << t[i];
324  }
325  return os;
326 }
327 
328 inline tgTags operator+(tgTags lhs, const tgTags& rhs)
329 {
330  lhs += rhs;
331  return lhs;
332 }
333 
334 // Overload the + operator for strings too. tgTags should be able to be added
335 // to strings, with a string as the return result.
336 inline std::string operator+(tgTags tags, std::string str)
337 {
338  // Use the stringstream overloaded operator.
339  std::stringstream os;
340  os << tags << str;
341  return os.str();
342 }
343 // Similarly, have a + function with the operands flipped.
344 inline std::string operator+(std::string str, tgTags tags)
345 {
346  // Use the stringstream overloaded operator.
347  std::stringstream os;
348  os << str << tags;
349  return os.str();
350 }
351 
356 inline std::string asYamlList(const tgTags& tags)
357 {
358  std::stringstream os;
359  os << "[";
360  for(size_t i = 0; i < tags.size(); i++) {
361  os << '"' << tags[i] << '"';
362  if(i != tags.size() - 1)
363  os << ", ";
364  }
365  os << "]";
366  return os.str();
367 };
368 
369 inline bool operator< (const tgTags& lhs, const tgTags& rhs){ return lhs.asSet() < rhs.asSet(); }
370 inline bool operator> (const tgTags& lhs, const tgTags& rhs){return rhs < lhs;}
371 inline bool operator<=(const tgTags& lhs, const tgTags& rhs){return !(lhs > rhs);}
372 inline bool operator>=(const tgTags& lhs, const tgTags& rhs){return !(lhs < rhs);}
373 
374 
375 #endif
std::string asYamlList(const tgTags &tags)
Definition: tgTags.h:356
std::ostream & operator<<(std::ostream &os, const tgTags &tags)
Definition: tgTags.h:316
bool isIntegery(const std::string s) const
Definition: tgTags.h:156
static std::deque< std::string > splitTags(const std::deque< std::string > &s, char delim= ' ')
Definition: tgTags.h:130
bool operator==(const tgTags &rhs)
Definition: tgTags.h:225
const std::set< std::string > asSet() const
Definition: tgTags.h:203
std::string & operator[](int key)
Definition: tgTags.h:214
Extension of std::exception for use within the library.
Definition: tgTags.h:44