event-driven
vBottle.h
1 /*
2  * Copyright (C) 2017 Event-driven Perception for Robotics
3  * Author: arren.glover@iit.it
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef __VBOTTLE__
20 #define __VBOTTLE__
21 
22 #include <yarp/os/Bottle.h>
23 #include <yarp/os/Log.h>
24 #include <yarp/os/LogStream.h>
25 #include <yarp/os/ConnectionWriter.h>
26 #include "event-driven/vCodec.h"
27 #include <iostream>
28 
29 namespace ev {
30 
33 class vBottle : public yarp::os::Bottle {
34 
35 public:
36 
37  //constructors shouldn't change from Bottle
39  vBottle() : yarp::os::Bottle() {}
40 
41  //you can only modify contents by adding events and append other vBottles
43  void addEvent(event<> e) {
44 
45  //first append a searchable string
46  //yarp::os::Bottle::addString(e.getType());
47  yarp::os::Bottle * b = yarp::os::Bottle::find(e->getType()).asList();
48 
49  if(!b) {
50  yarp::os::Bottle::addString(e->getType());
51  b = &(yarp::os::Bottle::addList());
52  }
53 
54  //add the coded event to the end of the bottle
55  e->encode(*b);
56  //b->append(e.encode());
57 
58  }
60  void append(vBottle &eb)
61  {
62  append<vEvent>(eb);
63  }
64 
66  template<class T> void append(vBottle &eb)
67  {
68 
69  //for each list of events
70  for(size_t tagi = 0; tagi < eb.yarp::os::Bottle::size(); tagi+=2) {
71 
72  //get the appended event type
73  const std::string tagname =
74  eb.yarp::os::Bottle::get(tagi).asString();
75  if(!tagname.size()) {
76  yError() << "Could not get tagname during vBottle append."
77  "Check vBottle integrity.";
78  continue;
79  }
80 
81  //check to see if we want to append this event type
82  event<> e = createEvent(tagname);
83  if(!e) {
84  std::cerr << "Warning: could not get bottle type during vBottle::"
85  "append<>(). Check vBottle integrity." << std::endl;
86  continue;
87  }
88  if(!std::dynamic_pointer_cast<T>(e)) continue;
89 
90 
91  //we want to append these events so get the data from bb
92  yarp::os::Bottle *b_from = eb.yarp::os::Bottle::get(tagi+1).asList();
93  if(!b_from->size()) {
94  std::cerr << "Warning: From-list empty during vBottle append."
95  "Check vBottle integrity." << std::endl;
96  continue;
97  }
98 
99  //get the correct bottle to append to (or create a new one)
100  yarp::os::Bottle *b_to = yarp::os::Bottle::find(tagname).asList();
101  if(!b_to) {
102  yarp::os::Bottle::addString(tagname);
103  b_to = &(yarp::os::Bottle::addList());
104  }
105 
106  //and do it
107  b_to->append(*b_from);
108  }
109 
110  }
111 
112  //all get functions call this to do the meat of the getting function
114  template<class T> vQueue get() {
115 
116  vQueue q;
117  addtoendof<T>(q);
118  return q;
119 
120  }
121 
124  template<class T> void addtoendof(vQueue &q) {
125 
126  //the bottle is stored as TAG (EVENTS) TAG (EVENTS)
127  for(size_t i = 0; i < Bottle::size(); i+=2) {
128 
129  //so for each TAG we create an event of that type
130  event<> e = createEvent(Bottle::get(i).asString());
131  if(!e) {
132  yError() << "Warning: could not get bottle type during vBottle::"
133  "get<>(). Check vBottle integrity.";
134  continue;
135  }
136 
137  //and if e is of type T we can continue to get the events
138  if(!std::dynamic_pointer_cast<T>(e)) {
139  continue;
140  }
141 
142  //we get the (EVENTS)
143  Bottle * b = Bottle::get(i+1).asList();
144  if(!b) {
145  yError() << "Warning: could not get event data as a list after "
146  "getting correct tag (e.g. AE) in vBottle::getAll(). "
147  "Check vBottle integrity";
148  break;
149  }
150 
151  //and decode each one also creating the memory with clone
152  //NOTE: push_back seems as fast as preallocation for a deque
153  size_t pos_b = 0;
154  while(pos_b < b->size()) {
155  if(e->decode(*b, pos_b)) {
156  q.push_back(e->clone());
157  }
158  }
159  }
160 
161  }
162 
165  template<class T> vQueue getSorted()
166  {
167  vQueue q = get<T>();
168  qsort(q);
169  return q;
170  }
171 
173  vQueue getAll() {
174  vQueue q = this->get<vEvent>(); //all events are of type vEvent
175  return q;
176  }
177 
180  vQueue getAllSorted() {
181  vQueue q = getAll();
182  qsort(q, true);
183  return q;
184  }
185 
186  //you can also access the following functions
187  //not sure if some need to be blocked
188 
189 // Bottle::clear()
190 // Bottle::check()
191 // Bottle::fromBinary()
192 // Bottle::fromString()
193 // Bottle::getContext()
194 // Bottle::getMonitor()
195 // Bottle::getNullBottle()
196 // Bottle::getReadType()
197 // Bottle::getSpecialization();
198 // Bottle::getType()
199 // Bottle::getWriteType()
200 // Bottle::hasChanged()
201 // Bottle::isNull()
202 // Bottle::onCommencement()
203 // Bottle::onCompletion()
204 // Bottle::operator !=()
205 // Bottle::operator =()
206 // Bottle::operator ==()
207 // Bottle::setMonitor()
208 // Bottle::setNested()
209 // Bottle::size()
210 // Bottle::specialize()
211 // Bottle::Searchable
212 // Bottle::toBinary()
213 // Bottle::toString()
214 
215  using yarp::os::Bottle::find;
216 
217 private:
218 
219  //you cannot use any of the following functions
220  void add();
221  void addDict();
222  void addDouble();
223  void addInt();
224  void addList();
225  void addString();
226  void addVocab();
227  void fromString(const std::string& text);
228  void append(const yarp::os::Bottle &alt);
229  void copy();
230  void copyPortable();
231  //yarp::os::Value& find(const yarp::os::ConstString &key);
232  //yarp::os::Value& find(const ConstString &key) : Bottle::find(const yarp::os::ConstString &key) {};
233  //Bottle& findGroup(const yarp::os::ConstString& key) const;
234  //void findGroup();
235 
236  using yarp::os::Bottle::findGroup;
237 
238  yarp::os::Bottle tail() const;
239 
240 
241  int getInt();
242  std::string getString();
243  double getDouble();
244  Bottle* getList();
245  yarp::os::Value& get();
246 
247  yarp::os::Value pop();
248 
249 };
250 
254 class vBottleMimic : public yarp::os::Portable {
255 
256 private:
257 
258  //headers
259  std::vector<std::int32_t> header1;
260  std::string header2;
261  std::vector<std::int32_t> header3;
262 
263  //data
264  const char * datablock;
265  unsigned int datalength; //<- set the number of bytes here
266  std::vector<std::int32_t> internaldata;
267 
268  //sizes
269  unsigned int elementINTS;
270  unsigned int elementBYTES;
271 
272 public:
273 
276  header1.push_back(BOTTLE_TAG_LIST); //bottle code
277  header1.push_back(2); //elements in bottle "AE" then bottle data
278  header1.push_back(BOTTLE_TAG_STRING); //code for string
279  header1.push_back(2); // length of string
280  header2 = "AE";
281  header3.push_back(BOTTLE_TAG_LIST|BOTTLE_TAG_INT); // bottle code + specialisation with ints
282  header3.push_back(0); // <- set the number of ints here (e.g. 2 * #v's)
283  elementINTS = 2;
284  elementBYTES = sizeof(std::int32_t) * elementINTS;
285  }
286 
289  void setExternalData(const char * datablock, unsigned int datalength) {
290  header3[1] = elementINTS * (datalength / elementBYTES); //forced to be x8
291  this->datablock = datablock;
292  this->datalength = elementBYTES * header3[1] / elementINTS; //forced to be x8
293 
294  }
295 
297  void setInternalData(const vQueue &q) {
298 
299  header3[1] = elementINTS * q.size(); //number of ints
300 
301  if((int)internaldata.size() < header3[1]) //increase internal mem if needed
302  internaldata.resize(header3[1]);
303 
304  unsigned int pos = 0;
305  for(unsigned int i = 0; i < q.size(); i++) //decode the data into
306  q[i]->encode(internaldata, pos); //internal memeory
307 
308  if(pos != (unsigned int)header3[1])
309  yError() << "vBottleMimic: encoding incorrect";
310 
311  this->datablock = (const char *)internaldata.data();
312  this->datalength = elementBYTES * q.size();
313  }
314 
316  void setHeader(std::string eventtype) {
317  header1[3] = eventtype.size(); //set the string length
318  header2 = eventtype; //set the string itself
319 
320  //get the elementsize THIS COULD BE MORE ELEGENT!!
321  yarp::os::Bottle temp;
322  event<> v = ev::createEvent(eventtype);
323  v->encode(temp);
324  elementINTS = temp.size();
325  elementBYTES = sizeof(std::int32_t) * elementINTS;
326 
327  }
328 
330  virtual bool read(yarp::os::ConnectionReader& connection) {
331  return false;
332  }
333 
335  virtual bool write(yarp::os::ConnectionWriter& connection) const {
336 
337  connection.appendBlock((const char *)header1.data(),
338  header1.size() * sizeof(std::int32_t));
339  connection.appendBlock(header2.c_str(), header1[3]);
340  connection.appendBlock((const char *)header3.data(),
341  header3.size() * sizeof(std::int32_t));
342  connection.appendBlock(datablock, datalength);
343 
344  return !connection.isError();
345  }
346 
347 };
348 
349 } //end namespace ev
350 
351 #endif /*__vBottle__*/
352 
353 //----- end-of-file --- ( next line intentionally left blank ) ------------------
Definition: vBottle.h:29
yarp::os::Bottle wrapper for sending events through the yarp system with ensuring compatibility with ...
Definition: vBottle.h:33
virtual bool write(yarp::os::ConnectionWriter &connection) const
write the data on the connection.
Definition: vBottle.h:335
vBottle()
default constructor
Definition: vBottle.h:39
a vBottle that avoids memory allocation where possible and can be correctly decoded when read from a ...
Definition: vBottle.h:254
virtual bool read(yarp::os::ConnectionReader &connection)
does nothing as this is a write-only port.
Definition: vBottle.h:330
vQueue getAll()
decode all events into a vQueue
Definition: vBottle.h:173
void addtoendof(vQueue &q)
add a specific event-type from the vBottle to the end of a vQueue
Definition: vBottle.h:124
vQueue getSorted()
get a specific event-type and ensure they are in correct temporal order
Definition: vBottle.h:165
void append(vBottle &eb)
append
Definition: vBottle.h:66
vQueue getAllSorted()
decode all events into a vQueue and ensure they are in correct temporal order
Definition: vBottle.h:180
void setInternalData(const vQueue &q)
send an entire vQueue. The queue is encoded and allocated into a single contiguous memory space...
Definition: vBottle.h:297
void append(vBottle &eb)
add all the contents of a vBottle to the current vBottle
Definition: vBottle.h:60
void setHeader(std::string eventtype)
set the type of event that this vBottleMimic will send
Definition: vBottle.h:316
void addEvent(event<> e)
add a single event to the vBottle
Definition: vBottle.h:43
vBottleMimic()
instantiate the correct headers for a Bottle
Definition: vBottle.h:275
void setExternalData(const char *datablock, unsigned int datalength)
for data already allocated in contiguous space. Just send this data on a port without memory realloca...
Definition: vBottle.h:289