Babel
Epitech's C++ VoIP project
Message.hpp
Go to the documentation of this file.
1 //
2 // Created by cbihan on 28/09/2021.
3 //
4 
5 #pragma once
6 
9 #include <cstring>
10 #include <cstdint>
11 #include <vector>
12 #include <algorithm>
13 #include <iostream>
14 #include <bit>
15 
16 namespace Babel
17 {
18 
19  template<typename T>
21  {
23  T codeId;
25  uint32_t bodySize = 0;
26 
29  void handleEndianness();
30 
31 
32 // //! @brief The UNIX Timestamp of the creation of the message
33 // uint32_t timeStamp;
34  };
35 
36  template<typename T>
38  {
39  if constexpr(std::endian::native != std::endian::big) {
40  this->codeId = swapEndian<T>(this->codeId);
41  this->bodySize = swapEndian<uint32_t>(this->bodySize);
42  }
43  }
44 
45  template<typename T>
46  struct Message
47  {
51  std::vector<uint8_t> body;
52 
54  size_t size() const;
55 
57  template<typename DataType>
58  static Message<T> &GetBytes(Message<T> &msg, DataType &data, uint64_t size);
59 
60  static Message<T> &GetBytes(Message<T> &msg, std::string &data, uint64_t size);
61 
64  void reset();
65 
67  explicit Message();
68 
70  Message(const Message<T> &m) = default;
71 
73  ~Message() = default;
74 
76  Message &operator=(const Message<T> &) = default;
77  };
78 
79 
80  template<typename T>
81  size_t Message<T>::size() const
82  {
83  return this->body.size();
84  }
85 
86  template<typename T>
87  template<typename DataType>
88  Message<T> &Message<T>::GetBytes(Message<T> &msg, DataType &data, uint64_t size)
89  {
90  static_assert(std::is_standard_layout<DataType>::value, "Data is too complex to be pulled from vector");
91 
92  if (size > msg.body.size()) {
93  throw Exception::BabelException("GetBytes: the size was superior than the message size");
94  }
95 
96  size_t i = msg.body.size() - size;
97  std::memmove(&data, msg.body.data(), size);
98  msg.body.assign(msg.body.begin() + size, msg.body.end());
99  if constexpr(std::endian::native != std::endian::big) {
100  data = swapEndian<DataType>(data);
101  }
102  msg.body.resize(i);
103  msg.header.bodySize = msg.size();
104 
105  return msg;
106  }
107 
108  template<typename T>
109  Message<T> &Message<T>::GetBytes(Message<T> &msg, std::string &data, uint64_t size)
110  {
111  if (size > msg.body.size()) {
112  throw Exception::BabelException("GetBytes: the size was superior than the message size");
113  }
114 
115  size_t i = msg.body.size() - size;
116 
117  data.assign(reinterpret_cast<char *>(msg.body.data()), size);
118  msg.body.assign(msg.body.begin() + size, msg.body.end());
119  if constexpr(std::endian::native != std::endian::big) {
120  std::reverse(data.begin(), data.end());
121  }
122  msg.body.resize(i);
123  msg.header.bodySize = msg.body.size();
124 
125  return msg;
126  }
127 
128  template<typename T>
130  : header({}),
131  body({})
132  {
133  }
134 
135  template<typename T>
137  {
138  this->header.bodySize = 0;
139  this->body.clear();
140  }
141 
142  template<typename T>
143  std::ostream &operator<<(std::ostream &os, const Message<T> &msg)
144  {
145  os << "ID:" << int(msg.header.codeId) << " Size:" << msg.header.bodySize;
146  return os;
147  }
148 
149  template<typename T, typename DataType>
150  Message<T> &operator<<(Message<T> &msg, DataType data)
151  {
152  static_assert(std::is_standard_layout<DataType>::value, "Data is too complex to be pushed into vector");
153 
154  size_t i = msg.body.size();
155 
156  msg.body.resize(msg.body.size() + sizeof(DataType));
157  if constexpr(std::endian::native != std::endian::big) {
158  data = swapEndian<DataType>(data);
159  }
160 
161  std::memmove(msg.body.data() + i, &data, sizeof(DataType));
162  msg.header.bodySize = msg.size();
163  return msg;
164  }
165 
166  template<typename T>
167  Message<T> &operator<<(Message<T> &msg, std::string data)
168  {
169 
170  size_t i = msg.body.size();
171 
172  msg.body.resize(msg.body.size() + data.size());
173  if constexpr(std::endian::native != std::endian::big) {
174  std::reverse(data.begin(), data.end());
175  }
176 
177  std::memmove(msg.body.data() + i, data.data(), data.size());
178  msg.header.bodySize = msg.size();
179  return msg;
180  }
181 
182  template<typename T>
183  Message<T> &operator<<(Message<T> &msg, const char data[])
184  {
185  return msg << std::string(data);
186  }
187 
188  template<typename T, typename DataType>
189  Message<T> &operator>>(Message<T> &msg, DataType &data)
190  {
191  return Message<T>::GetBytes(msg, data, sizeof(DataType));
192  }
193 }
Babel::Exception::BabelException
Base Project Exception.
Definition: BabelException.hpp:12
Babel::MessageHeader::handleEndianness
void handleEndianness()
Transform to network endianness the MessageHeader.
Definition: Message.hpp:37
Babel::Message::header
MessageHeader< T > header
The message metadata.
Definition: Message.hpp:49
Babel::MessageHeader
Definition: Message.hpp:20
Babel::operator>>
Message< T > & operator>>(Message< T > &msg, DataType &data)
Definition: Message.hpp:189
Babel::Message::size
size_t size() const
Returns the message body size.
Definition: Message.hpp:81
Babel::Message
Definition: Message.hpp:46
Babel::Message::reset
void reset()
Reset this message, this message will be totally empty.
Definition: Message.hpp:136
SwapEndian.hpp
Babel
Definition: IAudioManager.hpp:13
Babel::Message::Message
Message()
ctor
Definition: Message.hpp:129
Babel::MessageHeader::codeId
T codeId
The code id of the message to known what it's taking about.
Definition: Message.hpp:23
Babel::operator<<
Message< T > & operator<<(Message< T > &msg, const char data[])
Definition: Message.hpp:183
Babel::Message::body
std::vector< uint8_t > body
The payload of the message look at the header to know it's size.
Definition: Message.hpp:51
BabelException.hpp
Babel::Message::operator=
Message & operator=(const Message< T > &)=default
assignment ctor
Babel::MessageHeader::bodySize
uint32_t bodySize
The size of the message body in bytes.
Definition: Message.hpp:25
Babel::Message::GetBytes
static Message< T > & GetBytes(Message< T > &msg, DataType &data, uint64_t size)
Get size bytes from the message and put it in data, useful for strings (no compile time size)
Definition: Message.hpp:88
Babel::Message::~Message
~Message()=default
dtor