iLab Neuromorphic Robotics Toolkit  0.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AnyMessageImpl.H
Go to the documentation of this file.
1 /*! @file
2  @author Laurent Itti
3  @copyright GNU Public License (GPL v3)
4  @section License
5  @verbatim
6  // ////////////////////////////////////////////////////////////////////////
7  // The iLab Neuromorphic Robotics Toolkit (NRT) //
8  // Copyright 2010-2012 by the University of Southern California (USC) //
9  // and the iLab at USC. //
10  // //
11  // iLab - University of Southern California //
12  // Hedco Neurociences Building, Room HNB-10 //
13  // Los Angeles, Ca 90089-2520 - USA //
14  // //
15  // See http://ilab.usc.edu for information about this project. //
16  // ////////////////////////////////////////////////////////////////////////
17  // This file is part of The iLab Neuromorphic Robotics Toolkit. //
18  // //
19  // The iLab Neuromorphic Robotics Toolkit is free software: you can //
20  // redistribute it and/or modify it under the terms of the GNU General //
21  // Public License as published by the Free Software Foundation, either //
22  // version 3 of the License, or (at your option) any later version. //
23  // //
24  // The iLab Neuromorphic Robotics Toolkit is distributed in the hope //
25  // that it will be useful, but WITHOUT ANY WARRANTY; without even the //
26  // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
27  // PURPOSE. See the GNU General Public License for more details. //
28  // //
29  // You should have received a copy of the GNU General Public License //
30  // along with The iLab Neuromorphic Robotics Toolkit. If not, see //
31  // <http://www.gnu.org/licenses/>. //
32  // ////////////////////////////////////////////////////////////////////////
33  @endverbatim */
34 
35 
36 #ifndef INCLUDE_NRT_CORE_BLACKBOARD_DETAILS_ANYMESSAGEIMPL_H
37 #define INCLUDE_NRT_CORE_BLACKBOARD_DETAILS_ANYMESSAGEIMPL_H
38 
41 
42 // Define a bunch of macros
44 
45 #include <sstream>
46 
47 // ######################################################################
48 // ######################################################################
49 // ######################################################################
50 // AnyMessage implementation
51 // ######################################################################
52 // ######################################################################
53 // ######################################################################
54 
55 template <class Msg> inline
56 nrt::AnyMessage::AnyMessage(std::shared_ptr<Msg const> msg) :
57  nrt::MessageBase(), msgtype(nrt::MessageType<Msg>()), sermsg(), msgbase(msg)
58 {
59 #define BBWHAT "Construct AnyMessage containing [" + msgtype + ']'
60 
61  serfunc = [this]()
62  {
63  // NOTE: caller should ensure proper locking.
64  if ( ! this->msgbase) BBTHROWX(BadAnyMessageCast, "Cannot serialize empty AnyMessage");
65 
66  // Cast from our base pointer to full derived message type:
67  std::shared_ptr<Msg const> msg = std::dynamic_pointer_cast<Msg const>(msgbase);
68  if (!msg) BBTHROW(BadAnyMessageCast);
69 
70  // Serialize message into sermsg by using an ostringstream:
71  std::ostringstream os;
72  nrt::oarchive archive(os);
73  archive( *msg );
74  this->sermsg = os.str(); // that should be a move-assignment
75  };
76 
77 #undef BBWHAT
78 }
79 
80 // ######################################################################
81 inline nrt::AnyMessage::AnyMessage() // everything gets default-constructed
82 { }
83 
84 // ######################################################################
86 { }
87 
88 // ######################################################################
89 inline std::string const & nrt::AnyMessage::typeStr() const
90 { return msgtype; }
91 
92 // ######################################################################
93 template <class Msg> inline
94 typename std::shared_ptr<Msg const> nrt::AnyMessage::get() const
95 {
96 #define BBWHAT "Get AnyMessage containing [" + msgtype + "] as [" + nrt::MessageType<Msg>() + ']'
97 
98  // Requesting a wrong type? if so we throw:
99  if (msgtype.compare(nrt::MessageType<Msg>()) != 0) BBTHROW(BadAnyMessageCast);
100 
101  // If msgbase is not null, we already have the message in de-serialized form, let's just return it:
102  if (msgbase) // FIXME: assumes assignment below is atomic, could more strongly lock if needed
103  {
104  // First, from our base message pointer, cast message back to its full derived type:
105  std::shared_ptr<Msg const> msg = std::dynamic_pointer_cast<Msg const>(msgbase);
106  if (!msg) BBTHROW(BadAnyMessageCast);
107 
108  // Return full derived message:
109  return msg;
110  }
111 
112  // If sermsg is null, then we had no data, that's bad:
113  if (sermsg.empty()) BBTHROWX(BadAnyMessageCast, "Cannot handle empty AnyMessage");
114 
115  // Otherwise, let's de-serialize this puppy once and for all. Get unique lock:
116  std::lock_guard<std::mutex> lck(mtx);
117 
118  std::shared_ptr<Msg const> msg(new Msg);
119  try
120  {
121  std::istringstream is(sermsg);
122  nrt::iarchive ar(is);
123  ar( *(const_cast<Msg *>(msg.get())) );
124  }
125  catch (cereal::Exception const & e)
126  {
127  BBTHROWX(MessageSerializationError, e.what());
128  }
129  catch (...)
130  {
131  BBTHROW(MessageSerializationError);
132  }
133 
134  // Ok, it's de-serialized, keep a pointer to the base message for future use:
135  msgbase = msg;
136 
137  // Return the full derived message:
138  return msg;
139 
140 #undef BBWHAT
141 }
142 
143 // ######################################################################
144 template <class Archive> inline
145 void nrt::AnyMessage::load(Archive & ar)
146 {
147 #define BBWHAT "load AnyMessage containing [" + msgtype + ']'
148 
149  std::lock_guard<std::mutex> lck(mtx);
150 
151  ar( msgtype, sermsg );
152 
153  msgbase.reset(); // invalidated
154  serfunc = std::function<void()>(); // invalidated
155 
156 #undef BBWHAT
157 }
158 
159 // ######################################################################
160 template <class Archive> inline
161 void nrt::AnyMessage::save(Archive & ar) const
162 {
163 #define BBWHAT "save AnyMessage containing [" + msgtype + ']'
164 
165  std::lock_guard<std::mutex> lck(mtx);
166 
167  // store the message type:
168  ar( msgtype );
169 
170  // If the message is already known in serialized form, just store that, otherwise serialize and store:
171  if (sermsg.empty()) { if (serfunc) serfunc(); else BBTHROW(BadAnyMessageCast); }
172  ar( sermsg );
173 
174 #undef BBWHAT
175 }
176 
177 
178 // Un-define a bunch of macros
180 
181 #endif // INCLUDE_NRT_CORE_BLACKBOARD_DETAILS_ANYMESSAGEIMPL_H
182