Main Page · Modules · All Classes · Class Hierarchy
MCDataContainer.cpp
1 /*
2  * This file is part of the AiBO+ project
3  *
4  * Copyright (C) 2005-2016 Csaba Kertész (csaba.kertesz@gmail.com)
5  *
6  * AiBO+ is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * AiBO+ is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
19  *
20  */
21 
22 #include "MCDataContainer.hpp"
23 
24 #include "MCBinaryData.hpp"
25 #include "MCDataStorage.hpp"
26 #include "MCLog.hpp"
27 #include "MCTypes.hpp"
28 
29 #include <boost/iostreams/device/back_inserter.hpp>
30 #include <boost/iostreams/stream.hpp>
31 
32 MCDataItemBase::MCDataItemBase() : DataPtr(nullptr)
33 {
34 }
35 
36 
37 MCDataItemBase::~MCDataItemBase()
38 {
39 }
40 
41 
42 void MCDataItemBase::LoadFromArchive(boost::archive::binary_iarchive& archive)
43 {
44  MC_UNUSED(archive)
45 }
46 
47 
48 void MCDataItemBase::SaveToArchive(boost::archive::binary_oarchive& archive) const
49 {
50  MC_UNUSED(archive)
51 }
52 
53 
54 void MCDataItemBase::LoadFromArchive(eos::portable_iarchive& archive)
55 {
56  MC_UNUSED(archive)
57 }
58 
59 
60 void MCDataItemBase::SaveToArchive(eos::portable_oarchive& archive) const
61 {
62  MC_UNUSED(archive)
63 }
64 
65 
66 void MCDataItemBase::DeleteData()
67 {
68 }
69 
70 
71 MCDataContainer::MCDataContainer(const std::string& name, bool portable) : Name(name),
72  Portable(portable)
73 {
74  if (unlikely(MCDataStorage::IsVerbose()))
75  {
76  MC_LOG("Container: %s - ctor", Name.c_str());
77  }
78 }
79 
80 
82 {
83  if (unlikely(MCDataStorage::IsVerbose()))
84  {
85  MC_LOG("Container: %s - dtor", Name.c_str());
86  }
87  Clear();
88 }
89 
90 
92 {
93  return Portable;
94 }
95 
96 
98 {
99  for (auto& item : Items)
100  {
101  item->DeleteData();
102  delete item;
103  }
104  Items.clear();
105 }
106 
107 
108 std::string MCDataContainer::GetName() const
109 {
110  return Name;
111 }
112 
113 
115 {
116  // Huh, idea is from:
117  // http://boost.2283326.n4.nabble.com/in-memory-stream-binary-archive-serialization-td2578880.html
118  std::vector<char> TempBuffer;
119 
120  boost::iostreams::stream<boost::iostreams::back_insert_device<std::vector<char> > > OutStream(TempBuffer);
121  {
122  if (Portable)
123  {
124  eos::portable_oarchive OutputArchive(OutStream);
125 
126  OutputArchive << *this;
127  } else {
128  boost::archive::binary_oarchive OutputArchive(OutStream);
129 
130  OutputArchive << *this;
131  }
132  }
133  MCBinaryData* BinaryData = new MCBinaryData((int)TempBuffer.size());
134 
135  memcpy(BinaryData->GetData(), &TempBuffer[0], TempBuffer.size());
136  return BinaryData;
137 }
138 
139 
141  MCDataContainer* instance)
142 {
143  boost::iostreams::basic_array_source<char> Source((char*)data.GetData(), (std::size_t)data.GetSize());
144  boost::iostreams::stream<boost::iostreams::basic_array_source<char> > InStream(Source);
145  MCDataContainer* DataContainer = instance ? instance : new MCDataContainer("SpecialNameLoad", portable);
146 
147  if (portable)
148  {
149  MC_TRY_BEGIN_1(1)
150  eos::portable_iarchive InputArchive(InStream);
151 
152  InputArchive >> *DataContainer;
153  MC_CATCH_BEGIN_1(1)
154  // Destroy the newly allocated container
155  if (!instance)
156  {
157  delete DataContainer;
158  DataContainer = nullptr;
159  }
160  return nullptr;
161  MC_CATCH_END_1(1)
162  } else {
163  MC_TRY_BEGIN_1(2)
164  boost::archive::binary_iarchive InputArchive(InStream);
165 
166  InputArchive >> *DataContainer;
167  MC_CATCH_BEGIN_1(2)
168  // Destroy the newly allocated container
169  if (!instance)
170  {
171  delete DataContainer;
172  DataContainer = nullptr;
173  }
174  return nullptr;
175  MC_CATCH_END_1(2)
176  }
177  return DataContainer;
178 }
179 
180 
182 {
183  printf("Data container: %s\n", Name.c_str());
184  std::string DebugStr = "Data: ";
185 
186  for (auto& item : Items)
187  {
188  DebugStr += item->DataName+", ";
189  }
190  DebugStr.erase(DebugStr.size()-2, 2);
191  printf("%s\n", DebugStr.c_str());
192 }
193 
194 
195 MC::StringList MCDataContainer::GetDataNames() const
196 {
197  MC::StringList DataNames;
198 
199  for (auto& item : Items)
200  {
201  DataNames.push_back(item->DataName);
202  }
203  return DataNames;
204 }
205 
206 
208 {
209  // Remove an old data with the same name
210  for (auto iter = Items.begin(); iter != Items.end(); ++iter)
211  {
212  if ((*iter)->DataName == item.DataName)
213  {
214  (*iter)->DeleteData();
215  delete *iter;
216  Items.erase(iter);
217  break;
218  }
219  }
220  Items.push_back(&item);
221 }
222 
223 
224 MCDataItemBase* MCDataContainer::GetData(const std::string& data_name)
225 {
226  for (auto item : Items)
227  {
228  if (item->DataName == data_name)
229  {
230  return item;
231  }
232  }
233  return nullptr;
234 }
235 
236 
237 const MC::DataItemBasePtrList& MCDataContainer::GetAllData() const
238 {
239  return Items;
240 }
241 
242 
243 void MCDataContainer::RemoveData(const std::string& data_name)
244 {
245  for (auto iter = Items.begin(); iter != Items.end(); ++iter)
246  {
247  if ((*iter)->DataName == data_name)
248  {
249  (*iter)->DeleteData();
250  Items.erase(iter);
251  return;
252  }
253  }
254 }
255 
256 
258  const std::string& data_name)
259 {
260  MC_UNUSED(type_name);
261  MC_UNUSED(data_name);
262  return nullptr;
263 }
264 
265 
266 template<class Archive>
267 void MCDataContainer::load(Archive& archive, const unsigned int version)
268 {
269  MC_UNUSED(version);
270  // Container ID
271  std::string ContainerID;
272 
273  archive & ContainerID;
274  if (ContainerID != "DataContainer")
275  {
276  MC_WARNING("The archive does not contain a data container.");
277  return;
278  }
279  // Name
280  archive & Name;
281  // Number of items
282  int ItemCount = 0;
283 
284  archive & ItemCount;
285  for (int i = 0; i < ItemCount; ++i)
286  {
287  std::string DataName;
288  std::string TypeName;
289  MCDataItemBase* NewItem = nullptr;
290 
291  archive & DataName;
292  archive & TypeName;
293 
294 #define MA_DATA_ITEM_LOAD(_basic_type) \
295  if (TypeName == std::string(#_basic_type)) \
296  { \
297  NewItem = new MCDataItem<_basic_type>(*new _basic_type, DataName, false); \
298  } else
299 #define MA_DATA_ITEM_CONTAINER_LOAD(_container, _basic_type) \
300  if (TypeName == std::string(#_container)+'<'+#_basic_type+", std::allocator<"+#_basic_type+"> >") \
301  { \
302  NewItem = new MCDataItem<_container<_basic_type> >(*new _container<_basic_type>, DataName, false); \
303  } else
304 #define MA_DATA_ITEM_TABLE_LOAD(_container, _basic_type) \
305  if (TypeName == std::string(#_container)+'<'+#_container+'<'+#_basic_type+", std::allocator<"+#_basic_type+"> >"+ \
306  ", std::allocator<"+#_container+'<'+#_basic_type+", std::allocator<"+#_basic_type+"> > > >") \
307  { \
308  NewItem = new MCDataItem<_container<_container<_basic_type> > >(*new _container<_container<_basic_type> >, DataName, false); \
309  } else
310 #define MA_DATA_ITEM_MAP_CONTAINER_LOAD(_map_container, _key_type, _value_type) \
311  if (TypeName == std::string(#_map_container)+'<'+#_key_type+", "+#_value_type+ \
312  ", std::less<"+#_key_type+">, std::allocator<std::pair<"+#_key_type+" const, "+#_value_type+"> > >") \
313  { \
314  NewItem = new MCDataItem<_map_container<_key_type, _value_type> > \
315  (*new _map_container<_key_type, _value_type>, DataName, false); \
316  } else
317 #define MA_DATA_ITEM_CONTAINER_LOAD_BASIC_TYPES(_container) \
318  MA_DATA_ITEM_CONTAINER_LOAD(_container, bool) \
319  MA_DATA_ITEM_CONTAINER_LOAD(_container, int) \
320  MA_DATA_ITEM_CONTAINER_LOAD(_container, float) \
321  MA_DATA_ITEM_CONTAINER_LOAD(_container, double) \
322  MA_DATA_ITEM_CONTAINER_LOAD(_container, char)
323 
324 #define MA_DATA_ITEM_CONTAINER_LOAD_OTHER_TYPES(_container) \
325  MA_DATA_ITEM_CONTAINER_LOAD(_container, short) \
326  MA_DATA_ITEM_CONTAINER_LOAD(_container, unsigned char) \
327  MA_DATA_ITEM_CONTAINER_LOAD(_container, unsigned short) \
328  MA_DATA_ITEM_CONTAINER_LOAD(_container, unsigned int) \
329  MA_DATA_ITEM_CONTAINER_LOAD(_container, uint8_t) \
330  MA_DATA_ITEM_CONTAINER_LOAD(_container, uint16_t) \
331  MA_DATA_ITEM_CONTAINER_LOAD(_container, uint32_t) \
332  MA_DATA_ITEM_CONTAINER_LOAD(_container, int8_t) \
333  MA_DATA_ITEM_CONTAINER_LOAD(_container, int16_t) \
334  MA_DATA_ITEM_CONTAINER_LOAD(_container, int32_t)
335 
336 #define MA_DATA_ITEM_TABLE_LOAD_BASIC_TYPES(_container) \
337  MA_DATA_ITEM_TABLE_LOAD(_container, bool) \
338  MA_DATA_ITEM_TABLE_LOAD(_container, int) \
339  MA_DATA_ITEM_TABLE_LOAD(_container, float) \
340  MA_DATA_ITEM_TABLE_LOAD(_container, double) \
341  MA_DATA_ITEM_TABLE_LOAD(_container, char)
342 
343 #define MA_DATA_ITEM_TABLE_LOAD_OTHER_TYPES(_container) \
344  MA_DATA_ITEM_TABLE_LOAD(_container, short) \
345  MA_DATA_ITEM_TABLE_LOAD(_container, unsigned char) \
346  MA_DATA_ITEM_TABLE_LOAD(_container, unsigned short) \
347  MA_DATA_ITEM_TABLE_LOAD(_container, unsigned int) \
348  MA_DATA_ITEM_TABLE_LOAD(_container, uint8_t) \
349  MA_DATA_ITEM_TABLE_LOAD(_container, uint16_t) \
350  MA_DATA_ITEM_TABLE_LOAD(_container, uint32_t) \
351  MA_DATA_ITEM_TABLE_LOAD(_container, int8_t) \
352  MA_DATA_ITEM_TABLE_LOAD(_container, int16_t) \
353  MA_DATA_ITEM_TABLE_LOAD(_container, int32_t)
354 
355  MA_DATA_ITEM_LOAD(bool)
356  MA_DATA_ITEM_LOAD(int)
357  MA_DATA_ITEM_LOAD(float)
358  MA_DATA_ITEM_LOAD(double)
359  MA_DATA_ITEM_LOAD(char)
360  // std::string must be handled separately because of the new C++ ABI since GCC 5.x
361  if (TypeName == MCGetClassName<std::string>() || TypeName == "std::string")
362  {
363  NewItem = new MCDataItem<std::string>(*new std::string, DataName, false);
364  } else
365  MA_DATA_ITEM_LOAD(MCBinaryData)
366  MA_DATA_ITEM_CONTAINER_LOAD_BASIC_TYPES(std::vector)
367  // std::string must be handled separately because of the new C++ ABI since GCC 5.x
368  if (TypeName == "std::vector<"+MCGetClassName<std::string>()+", std::allocator<"+MCGetClassName<std::string>()+" > >" ||
369  TypeName == "std::vector<std::string, std::allocator<std::string> >")
370  {
371  NewItem = new MCDataItem<std::vector<std::string> >(*new std::vector<std::string>, DataName, false);
372  } else
373  MA_DATA_ITEM_TABLE_LOAD_BASIC_TYPES(std::vector)
374  // std::string must be handled separately because of the new C++ ABI since GCC 5.x
375  if (TypeName == std::string("std::vector<std::vector<"+MCGetClassName<std::string>()+", std::allocator<"+MCGetClassName<std::string>()+" > >")+
376  ", std::allocator<std::vector<"+MCGetClassName<std::string>()+", std::allocator<"+MCGetClassName<std::string>()+" > > > >" ||
377  TypeName == std::string("std::vector<std::vector<std::string, std::allocator<std::string> >")+
378  ", std::allocator<std::vector<std::string, std::allocator<std::string> > > >")
379  {
380  NewItem = new MCDataItem<std::vector<std::vector<std::string> > >(*new std::vector<std::vector<std::string> >, DataName, false);
381  } else
382  MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, float, float)
383  // Note: Comment these types to avoid any performance hits
384 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, double, double)
385 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, int, float)
386 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, int, double)
387 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, int, int)
388 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, std::__cxx11::string, std::__cxx11::string)
389 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, std::__cxx11::string, int)
390 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, std::__cxx11::string, float)
391 // MA_DATA_ITEM_MAP_CONTAINER_LOAD(std::map, std::__cxx11::string, double)
392 // MA_DATA_ITEM_LOAD(short)
393 // MA_DATA_ITEM_LOAD(unsigned char)
394 // MA_DATA_ITEM_LOAD(unsigned short)
395 // MA_DATA_ITEM_LOAD(unsigned int)
396 // MA_DATA_ITEM_LOAD(uint8_t)
397 // MA_DATA_ITEM_LOAD(uint16_t)
398 // MA_DATA_ITEM_LOAD(uint32_t)
399 // MA_DATA_ITEM_LOAD(int8_t)
400 // MA_DATA_ITEM_LOAD(int16_t)
401 // MA_DATA_ITEM_LOAD(int32_t)
402 // MA_DATA_ITEM_CONTAINER_LOAD_OTHER_TYPES(std::vector)
403 // MA_DATA_ITEM_TABLE_LOAD_OTHER_TYPES(std::vector)
404 // MA_DATA_ITEM_CONTAINER_LOAD_BASIC_TYPES(std::list)
405 // MA_DATA_ITEM_CONTAINER_LOAD_OTHER_TYPES(std::list)
406 // MA_DATA_ITEM_TABLE_LOAD_BASIC_TYPES(std::list)
407  {
408  NewItem = GetInputArchiveDataType(TypeName, DataName);
409  }
410 #undef MA_DATA_ITEM_LOAD
411 #undef MA_DATA_ITEM_CONTAINER_LOAD
412 #undef MA_DATA_ITEM_CONTAINER_LOAD_BASIC_TYPES
413 #undef MA_DATA_ITEM_CONTAINER_LOAD_OTHER_TYPES
414 #undef MA_DATA_ITEM_TABLE_LOAD
415 #undef MA_DATA_ITEM_TABLE_LOAD_BASIC_TYPES
416 #undef MA_DATA_ITEM_TABLE_LOAD_OTHER_TYPES
417 
418  if (!NewItem)
419  {
420  MC_WARNING("Not supported type: %s -> Abort loading", TypeName.c_str());
421  return;
422  } else {
423  NewItem->LoadFromArchive(archive);
424  Items.push_back(NewItem);
425  NewItem = nullptr;
426  }
427  }
428 }
429 
430 
431 template<class Archive>
432 void MCDataContainer::save(Archive& archive, const unsigned int version) const
433 {
434  MC_UNUSED(version);
435  // Container ID
436  std::string ContainerID = "DataContainer";
437 
438  archive & ContainerID;
439  // Name
440  archive & Name;
441  // Number of items
442  int ItemCount = Items.size();
443 
444  archive & ItemCount;
445  for (auto& item : Items)
446  {
447  archive & item->DataName;
448  archive & item->TypeName;
449  item->SaveToArchive(archive);
450  }
451 }
452 
453 // Explicit template instantiation
454 // http://stackoverflow.com/questions/2152002/how-do-i-force-a-particular-instance-of-a-c-template-to-instantiate
455 // Post by Alexander Poluektov
456 template void MCDataContainer::load<boost::archive::binary_iarchive>(boost::archive::binary_iarchive&,
457  const unsigned int);
458 template void MCDataContainer::save<boost::archive::binary_oarchive>(boost::archive::binary_oarchive&,
459  const unsigned int) const;
460 template void MCDataContainer::load<eos::portable_iarchive>(eos::portable_iarchive&, const unsigned int);
461 template void MCDataContainer::save<eos::portable_oarchive>(eos::portable_oarchive&, const unsigned int) const;
virtual ~MCDataContainer()
Class destructor.
MCDataItemBase * GetData(const std::string &data_name)
Get a data item.
A helper class to fill the type info to the base structure.
void AddData(MCDataItemBase &item)
Add a new data item.
Data container.
Binary data class.
MC::DataItemBasePtrList Items
Data items.
bool IsPortable() const
Check if the data container is portable.
void Clear()
Clear the data container by destroying all data items.
void Dump() const
Dump container items.
#define MC_WARNING(...)
Warning macro.
Definition: MCLog.hpp:43
Data container item base structure to store basic type info.
static bool IsVerbose()
Get the verbosity of the data storage domain.
MCDataContainer(const std::string &name, bool portable=false)
Class constructor.
std::string GetName() const
Get the data container name.
#define MC_UNUSED(a)
Helper macro to avoid compiler warning about unused function parameters.
Definition: MCDefs.hpp:601
MC::StringList GetDataNames() const
Get data item names.
virtual MCDataItemBase * GetInputArchiveDataType(const std::string &type_name, const std::string &data_name)
Create a custom data type in a derived container.
static MCDataContainer * Decode(const MCBinaryData &data, bool portable=false, MCDataContainer *instance=nullptr)
Load the data container from binary form.
unsigned char * GetData() const
Get direct access to the binary data.
const MC::DataItemBasePtrList & GetAllData() const
Get all data items.
#define MC_LOG(...)
Debug macro.
Definition: MCLog.hpp:41
std::string Name
Data container name.
MCBinaryData * Encode() const
Save the data container into binary form.
bool Portable
Data container type (portable/non-portable)
void RemoveData(const std::string &data_name)
Remove a data item.
int GetSize() const
Get binary data size.