NTRT Simulator  Version: Master
 All Classes Namespaces Files Functions Variables Typedefs Friends Pages
tgTaggedNamedList.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_TAGGED_NAMED_LIST_H
27 #define TG_TAGGED_NAMED_LIST_H
28 
29 #include <iostream> // Testing only
30 #include <algorithm>
31 #include <vector>
32 #include <map>
33 #include <stdexcept>
34 #include "tgTaggable.h"
35 class tgTaggable;
36 
37 template <class T>
39 {
40 public:
41 
43  // Postcondition
44  assert(m_elements.empty());
45  };
46 
53  tgTaggedNamedList(std::vector<T>& elements) : m_elements(elements) {
54  // All elements must be unique
55  assertUniqueElements("All elements must be unique.");
56 
57  };
58 
59  virtual ~tgTaggedNamedList() {};
60 
65  std::vector<T*> find(std::string tags)
66  {
67  std::vector<T*> result;
68  for(int i = 0; i < m_elements.size(); i++) {
69  if(_taggable(&m_elements[i])->hasAllTags(tags)) {
70  result.push_back(&(m_elements[i]));
71  }
72  }
73  return result;
74  }
75 
76  int size() const
77  {
78  return m_elements.size();
79  }
80 
81  std::vector<T*> findAll()
82  {
83  std::vector<T*> result;
84  for(int i = 0; i < m_elements.size(); i++) {
85  result.push_back(&(m_elements[i]));
86  }
87  return result;
88  }
89 
90  std::vector<T*> findUntagged()
91  {
92  std::vector<T*> result;
93  for(int i = 0; i < m_elements.size(); i++) {
94  tgTaggable* t = _taggable(&m_elements[i]);
95  if(t->hasNoTags()) {
96  result.push_back(&(m_elements[i]));
97  }
98  }
99  return result;
100  }
101 
102  static bool contains(std::vector<T*> haystack, const T* needle)
103  {
104  return std::find(haystack.begin(), haystack.end(), needle) != haystack.end();
105  }
106 
107  bool contains(const T& needle) const
108  {
109  //return std::find(m_elements.begin(), m_elements.end(), needle) != m_elements.end(); // generates errors??
110  for(typename std::vector<T>::const_iterator it = m_elements.begin(); it != m_elements.end(); it++) {
111  if(&(*it) == &needle)
112  return true;
113  }
114  return false;
115  }
116 
123  T& operator[](int key) {
124  assertKeyExists(key);
125  return m_elements[key];
126  }
127 
128  const T& operator[](int key) const {
129  assertKeyExists(key);
130  return m_elements[key];
131  }
132 
139  T& operator[](const std::string& name) {
140  assertNameExists(name);
141  return this[name];
142  }
143 
147  /*
148  // @note: Need to refactor removeElements to take into account named
149  // elements. Commented out until that can happen.
150 
151  T& operator-=(const T& other) {
152  this->removeElements(other.getElements());
153  return *this;
154  }
155 
156  T& operator-=(const std::vector<T*> other) {
157  this->removeElements(other);
158  return *this;
159  }
160  */
161 
162  T& operator+=(const T& other) {
163  this->addElement(other);
164  return *this;
165  }
166 
167  T& operator+=(const std::vector<T*> other) {
168  this->addElements(other);
169  return *this;
170  }
171 
172 
173 protected:
174 
175  // @todo: think about uniqueness -- if not unique, throw an error? return -1?
176  int addElement(T element)
177  {
178  // @todo: make sure the element is unique
179  assert(!elementExists(element)); // segfault?
180  assertUnique(element);
181 
182  // Note: not thread safe
183  int idx = m_elements.size();
184  m_elements.push_back(element);
185  return idx; // This is the index that was created.
186  }
187 
188  int addElement(T element, std::string name)
189  {
190  assertNameUnused(name);
191  int idx = addElement(element);
192  m_names[name] = idx;
193  return idx;
194  }
195 
196  void addElements(std::vector<T*> elements)
197  {
198  for(int i = 0; i < elements.size(); i++) {
199  this->addElement(elements[i]);
200  }
201  }
202 
203  void setElement(int key, T element) {
204  assert((0 <= key) && (key <= m_elements.size()));
205  m_elements[key] = element;
206  }
207 
208  std::vector<T>& getElements()
209  {
210  return m_elements;
211  };
212 
213  const std::vector<T>& getElements() const
214  {
215  return m_elements;
216  };
217 
218  /*
219  // @note: disabling removal of elements until it can be refactored to
220  // account for named elements.
221  void removeElement(const T& element) {
222  m_elements.erase(std::remove(m_elements.begin(), m_elements.end(), element), m_elements.end());
223  }
224 
225  void removeElement(const T* element) {
226  m_elements.erase(std::remove(m_elements.begin(), m_elements.end(), *element), m_elements.end());
227  }
228 
229  void removeElements(const std::vector<T>& elements) {
230  for(int i = 0; i < elements.size(); i++) {
231  removeElement(elements[i]);
232  }
233  }
234 
235  void removeElements(const std::vector<T*>& elements) {
236  for(int i = 0; i < elements.size(); i++) {
237  removeElement(elements[i]);
238  }
239  }
240  */
241 
242  // To make subclassing operators easier...
243  T& getElement(int key)
244  {
245  return m_elements[key];
246  }
247 
248  // To make subclassing operators easier...
249  const T& getElement(int key) const
250  {
251  return m_elements[key];
252  }
253 
254 
255  T& getElement(std::string name)
256  {
257  assertNameExists(name);
258  return this[m_names[name]];
259  }
260 
264  int setNameIndex(const std::string& name, int idx)
265  {
266  m_names[name] = idx;
267  return idx; // @note: return the idx to help with fluent interfaces
268  }
269 
276  bool keyExists(int key) const
277  {
278  return (0 <= key) && (key < m_elements.size());
279  }
280 
281  bool nameExists(std::string name) const
282  {
283  return m_names.count(name) != 0;
284  }
285 
286  // @todo: FIX THIS -- segfaults, etc. -- what's going on?
287  bool elementExists(const T& element) const
288  {
289  //return std::find(m_elements.begin(), m_elements.end(), element) != m_elements.end(); // segfault?
290  for(int i = 0; i < m_elements.size(); i++) {
291  // This is a little strange to me, but at least it doesn't cause a segfault...
292  const T* elem =& m_elements[i];
293  if (elem == &element) {
294  return true;
295  }
296  }
297  return false;
298  }
299 
300  void assertKeyExists(int key, std::string message = "Element at index does not exist") const
301  {
302  if(!keyExists(key)) {
303  std::stringstream ss;
304  ss << key;
305  throw std::out_of_range(message + " (index "+ ss.str() + ").");
306  }
307  }
308 
309  void assertNameExists(std::string name, std::string message = "Name pointer does not exist") const
310  {
311  if(!nameExists(name)) {
312  std::stringstream ss;
313  ss << name;
314  throw std::out_of_range(message + " (name '"+ ss.str() + "').");
315  }
316  }
317 
318  void assertNameUnused(std::string name, std::string message = "Name already used") const
319  {
320  if(nameExists(name)) {
321  std::stringstream ss;
322  ss << name;
323  throw std::logic_error(message + " (name '"+ ss.str() + "').");
324  }
325  }
326 
327  void assertUnique(T& element, std::string message = "Taggable elements must be unique.") {
328  if(elementExists(element)) {
329  throw std::logic_error(message);
330  }
331  }
332 
333  void assertUniqueElements(std::string message = "Taggable elements must be unique.") const
334  {
335  /* Note: this throws a "Most vexing parse" error (http://en.wikipedia.org/wiki/Most_vexing_parse)
336  // Note: This would probably work if we implemented operator< on tgPair...
337  */
338 
339  if(! std::set<T>(m_elements.begin(), m_elements.end()).size() ==
340  m_elements.size()) {
341  throw std::logic_error(message);
342  }
343 
344  }
345 
346  // Cast T to taggable (after all, T must be a tgTaggable in the first place, but )
347  // there doesn't seem to be a way to enforce that with c++ templates...
348  tgTaggable* _taggable(T* obj) {
349  return static_cast<tgTaggable*>(obj);
350  }
351 
352 private:
353  std::vector<T> m_elements;
354  std::map<std::string, int> m_names;
355 };
356 
357 
358 #endif
std::vector< T * > find(std::string tags)
T & operator+=(const T &other)
Contains the definition of class tgTaggable.
T & operator[](const std::string &name)
tgTaggedNamedList(std::vector< T > &elements)
bool keyExists(int key) const
int setNameIndex(const std::string &name, int idx)
T & operator[](int key)