SimpleAI
 All Classes Namespaces Files Functions Variables Typedefs Macros Groups Pages
IProtocolMessage.h
Go to the documentation of this file.
1 
4 #pragma once
5 
6 #include <stdint.h>
7 #include <stddef.h>
8 #include <limits.h>
9 #include <string>
10 #include <deque>
11 #define AI_LIL_ENDIAN 1234
12 #define AI_BIG_ENDIAN 4321
13 #ifdef __linux__
14 #include <endian.h>
15 #define AI_BYTEORDER __BYTE_ORDER
16 #else
17 #define AI_BYTEORDER AI_LIL_ENDIAN
18 #endif
19 
20 #if AI_BYTEORDER == AI_LIL_ENDIAN
21 #define AI_SwapLE16(X) (X)
22 #define AI_SwapLE32(X) (X)
23 #define AI_SwapLE64(X) (X)
24 #define AI_SwapBE16(X) AI_Swap16(X)
25 #define AI_SwapBE32(X) AI_Swap32(X)
26 #define AI_SwapBE64(X) AI_Swap64(X)
27 #else
28 #define AI_SwapLE16(X) AI_Swap16(X)
29 #define AI_SwapLE32(X) AI_Swap32(X)
30 #define AI_SwapLE64(X) AI_Swap64(X)
31 #define AI_SwapBE16(X) (X)
32 #define AI_SwapBE32(X) (X)
33 #define AI_SwapBE64(X) (X)
34 #endif
35 
36 namespace ai {
37 
38 typedef uint8_t ProtocolId;
39 typedef std::deque<uint8_t> streamContainer;
40 
41 const ProtocolId PROTO_PING = 0;
42 const ProtocolId PROTO_STATE = 1;
43 const ProtocolId PROTO_CHARACTER_STATIC = 2;
44 const ProtocolId PROTO_CHARACTER_DETAILS = 3;
45 const ProtocolId PROTO_SELECT = 4;
46 const ProtocolId PROTO_PAUSE = 5;
47 const ProtocolId PROTO_CHANGE = 6;
48 const ProtocolId PROTO_NAMES = 7;
49 const ProtocolId PROTO_RESET = 8;
50 const ProtocolId PROTO_STEP = 9;
51 const ProtocolId PROTO_UPDATENODE = 10;
52 const ProtocolId PROTO_DELETENODE = 11;
53 const ProtocolId PROTO_ADDNODE = 12;
54 
61 private:
62 #if defined(__GNUC__) && defined(__i386__)
63  static inline uint16_t AI_Swap16(uint16_t x) {
64  __asm__("xchgb %b0,%h0": "=q"(x):"0"(x));
65  return x;
66  }
67 #elif defined(__GNUC__) && defined(__x86_64__)
68  static inline uint16_t AI_Swap16(uint16_t x) {
69  __asm__("xchgb %b0,%h0": "=Q"(x):"0"(x));
70  return x;
71  }
72 #else
73  static inline uint16_t AI_Swap16(uint16_t x) {
74  return static_cast<uint16_t>((x << 8) | (x >> 8));
75  }
76 #endif
77 
78 #if defined(__GNUC__) && defined(__i386__)
79  static inline uint32_t AI_Swap32(uint32_t x) {
80  __asm__("bswap %0": "=r"(x):"0"(x));
81  return x;
82  }
83 #elif defined(__GNUC__) && defined(__x86_64__)
84  static inline uint32_t AI_Swap32(uint32_t x) {
85  __asm__("bswapl %0": "=r"(x):"0"(x));
86  return x;
87  }
88 #else
89  static inline uint32_t AI_Swap32(uint32_t x) {
90  return static_cast<uint32_t>((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
91  }
92 #endif
93 
94 #if defined(__GNUC__) && defined(__i386__)
95  static inline uint64_t AI_Swap64(uint64_t x) {
96  union {
97  struct {
98  uint32_t a, b;
99  }s;
100  uint64_t u;
101  }v;
102  v.u = x;
103  __asm__("bswapl %0 ; bswapl %1 ; xchgl %0,%1": "=r"(v.s.a), "=r"(v.s.b):"0"(v.s.a), "1"(v.s. b));
104  return v.u;
105  }
106 #elif defined(__GNUC__) && defined(__x86_64__)
107  static inline uint64_t AI_Swap64(uint64_t x) {
108  __asm__("bswapq %0": "=r"(x):"0"(x));
109  return x;
110  }
111 #else
112  static inline uint64_t AI_Swap64(uint64_t x) {
113  /* Separate into high and low 32-bit values and swap them */
114  const uint32_t lo = static_cast<uint32_t>(x & 0xFFFFFFFF);
115  x >>= 32;
116  const uint32_t hi = static_cast<uint32_t>(x & 0xFFFFFFFF);
117  x = AI_Swap32(lo);
118  x <<= 32;
119  x |= AI_Swap32(hi);
120  return x;
121  }
122 #endif
123 
124 protected:
125  const ProtocolId _id;
126 
127 public:
128  static void addByte(streamContainer& out, uint8_t byte);
129  static void addBool(streamContainer& out, bool value);
130  static void addShort(streamContainer& out, int16_t word);
131  static void addInt(streamContainer& out, int32_t dword);
132  static void addLong(streamContainer& out, int64_t dword);
133  static void addFloat(streamContainer& out, float value);
134  static void addString(streamContainer& out, const std::string& string);
135 
136  static bool readBool(streamContainer& in);
137  static uint8_t readByte(streamContainer& in);
138  static int16_t readShort(streamContainer& in);
139  static int32_t peekInt(const streamContainer& in);
140  static int32_t readInt(streamContainer& in);
141  static int64_t readLong(streamContainer& in);
142  static float readFloat(streamContainer& in);
143  static std::string readString(streamContainer& in);
144 
145 public:
146  explicit IProtocolMessage(const ProtocolId& id) :
147  _id(id) {
148  }
149 
150  virtual ~IProtocolMessage() {
151  }
152 
153  inline const ProtocolId& getId() const {
154  return _id;
155  }
156 
157  virtual void serialize(streamContainer& out) const {
158  addByte(out, _id);
159  }
160 };
161 
162 inline void IProtocolMessage::addByte(streamContainer& out, uint8_t byte) {
163  out.push_back(byte);
164 }
165 
166 inline void IProtocolMessage::addBool(streamContainer& out, bool value) {
167  out.push_back(value);
168 }
169 
170 inline bool IProtocolMessage::readBool(streamContainer& in) {
171  return readByte(in) == 1;
172 }
173 
174 inline uint8_t IProtocolMessage::readByte(streamContainer& in) {
175  const uint8_t b = in.front();
176  in.pop_front();
177  return b;
178 }
179 
180 inline void IProtocolMessage::addFloat(streamContainer& out, float value) {
181  union toint {
182  float f;
183  int32_t i;
184  } tmp;
185  tmp.f = value;
186  addInt(out, tmp.i);
187 }
188 
189 inline float IProtocolMessage::readFloat(streamContainer& in) {
190  union toint {
191  float f;
192  int32_t i;
193  } tmp;
194  tmp.i = readInt(in);
195  return tmp.f;
196 }
197 
198 inline std::string IProtocolMessage::readString(streamContainer& in) {
199  std::string strbuff;
200  strbuff.reserve(64);
201  for (;;) {
202  const char chr = static_cast<char>(in.front());
203  in.pop_front();
204  if (chr == '\0')
205  break;
206  strbuff += chr;
207  }
208  return strbuff;
209 }
210 
211 inline void IProtocolMessage::addString(streamContainer& out, const std::string& string) {
212  const std::size_t length = string.length();
213  for (std::size_t i = 0; i < length; ++i) {
214  out.push_back(uint8_t(string[i]));
215  }
216  out.push_back(uint8_t('\0'));
217 }
218 
219 inline void IProtocolMessage::addShort(streamContainer& out, int16_t word) {
220  const int16_t swappedWord = AI_SwapLE16(word);
221  out.push_back(uint8_t(swappedWord));
222  out.push_back(uint8_t(swappedWord >> CHAR_BIT));
223 }
224 
225 inline void IProtocolMessage::addInt(streamContainer& out, int32_t dword) {
226  int32_t swappedDWord = AI_SwapLE32(dword);
227  out.push_back(uint8_t(swappedDWord));
228  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
229  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
230  out.push_back(uint8_t(swappedDWord >> CHAR_BIT));
231 }
232 
233 inline void IProtocolMessage::addLong(streamContainer& out, int64_t dword) {
234  int64_t swappedDWord = AI_SwapLE64(dword);
235  out.push_back(uint8_t(swappedDWord));
236  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
237  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
238  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
239  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
240  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
241  out.push_back(uint8_t(swappedDWord >>= CHAR_BIT));
242  out.push_back(uint8_t(swappedDWord >> CHAR_BIT));
243 }
244 
245 inline int16_t IProtocolMessage::readShort(streamContainer& in) {
246  uint8_t buf[2];
247  const int l = sizeof(buf);
248  for (int i = 0; i < l; ++i) {
249  buf[i] = in.front();
250  in.pop_front();
251  }
252  const int16_t *word = (const int16_t*) (void*) &buf;
253  const int16_t val = AI_SwapLE16(*word);
254  return val;
255 }
256 
257 inline int32_t IProtocolMessage::readInt(streamContainer& in) {
258  uint8_t buf[4];
259  const int l = sizeof(buf);
260  for (int i = 0; i < l; ++i) {
261  buf[i] = in.front();
262  in.pop_front();
263  }
264  const int32_t *word = (const int32_t*) (void*) &buf;
265  const int32_t val = AI_SwapLE32(*word);
266  return val;
267 }
268 
269 inline int32_t IProtocolMessage::peekInt(const streamContainer& in) {
270  uint8_t buf[4];
271  const int l = sizeof(buf);
272  streamContainer::const_iterator it = in.begin();
273  for (int i = 0; i < l; ++i) {
274  if (it == in.end())
275  return -1;
276  buf[i] = *it;
277  ++it;
278  }
279  const int32_t *word = (const int32_t*) (void*) &buf;
280  const int32_t val = AI_SwapLE32(*word);
281  return val;
282 }
283 
284 inline int64_t IProtocolMessage::readLong(streamContainer& in) {
285  uint8_t buf[8];
286  const int l = sizeof(buf);
287  for (int i = 0; i < l; ++i) {
288  buf[i] = in.front();
289  in.pop_front();
290  }
291  const int64_t *word = (const int64_t*) (void*) &buf;
292  const int64_t val = AI_SwapLE64(*word);
293  return val;
294 }
295 
296 #define PROTO_MSG(name, id) class name : public IProtocolMessage { public: name() : IProtocolMessage(id) {} }
297 
301 PROTO_MSG(AIResetMessage, PROTO_RESET);
305 PROTO_MSG(AIPingMessage, PROTO_PING);
306 }
A protocol message is used for the serialization of the ai states for remote debugging.
Definition: IProtocolMessage.h:60