]> git.mxchange.org Git - simgear.git/blob - simgear/hla/RTIData.hxx
hla: Use a different extrapolation method for HLALocation.
[simgear.git] / simgear / hla / RTIData.hxx
1 // Copyright (C) 2009 - 2010  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Library General Public License for more details.
12 //
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 //
17
18 #ifndef RTIData_hxx
19 #define RTIData_hxx
20
21 #include <cstring>
22 #include <list>
23 #include <simgear/misc/stdint.hxx>
24
25 namespace simgear {
26
27 /// Sigh, this is std::vector<char>, except that
28 /// you could feed that with external pointers without copying ...
29 /// Note on alignment: the c++ standard garantees (5.3.4.10) that
30 /// new (unsigned) char returns sufficiently aligned memory
31 /// for all relevant cases
32 class RTIData {
33 public:
34     RTIData() :
35         _data(0),
36         _size(0),
37         _capacity(0)
38     { }
39     RTIData(unsigned size) :
40         _data(0),
41         _size(0),
42         _capacity(0)
43     { resize(size); }
44     RTIData(char* data, unsigned size) :
45         _data(data),
46         _size(size),
47         _capacity(0)
48     { }
49     RTIData(const char* data, unsigned size) :
50         _data(0),
51         _size(0),
52         _capacity(0)
53     { setData(data, size); }
54     RTIData(const char* data) :
55         _data(0),
56         _size(0),
57         _capacity(0)
58     { setData(data); }
59     RTIData(const RTIData& data) :
60         _data(0),
61         _size(0),
62         _capacity(0)
63     {
64         unsigned size = data.size();
65         if (size) {
66             resize(size);
67             memcpy(_data, data.data(), size);
68         }
69     }
70     ~RTIData()
71     {
72         if (_capacity)
73             delete [] _data;
74         _data = 0;
75     }
76
77     const char* data() const
78     { return _data; }
79     char* data()
80     { return _data; }
81
82     unsigned size() const
83     { return _size; }
84
85     bool empty() const
86     { return _size == 0; }
87
88     void clear()
89     {
90         if (_capacity == 0) {
91             _data = 0;
92             _size = 0;
93         } else
94             resize(0);
95     }
96
97     void resize(unsigned size)
98     {
99         if (size == _size)
100             return;
101         if (_capacity < size) {
102             unsigned capacity = 2*_capacity;
103             if (size < capacity)
104                 ensureCapacity(capacity);
105             else
106                 ensureCapacity(size);
107         }
108         _size = size;
109     }
110
111     void reserve(unsigned capacity)
112     {
113         if (capacity <= _capacity)
114             return;
115         ensureCapacity(capacity);
116     }
117
118     void swap(RTIData& data)
119     {
120         std::swap(_data, data._data);
121         std::swap(_size, data._size);
122         std::swap(_capacity, data._capacity);
123     }
124
125     void setData(char* data, unsigned size)
126     {
127         if (_capacity)
128             delete [] _data;
129         _data = data;
130         _size = size;
131         _capacity = 0;
132     }
133     void setData(const char* data, unsigned size)
134     {
135         resize(size);
136         if (!size)
137             return;
138         memcpy(_data, data, size);
139     }
140     void setData(const char* data)
141     {
142         if (!data) {
143             setData("", 1);
144         } else {
145             size_t size = strlen(data) + 1;
146             setData(data, size);
147         }
148     }
149
150     RTIData& operator=(const RTIData& data)
151     {
152         unsigned size = data.size();
153         if (size) {
154             resize(size);
155             memcpy(_data, data.data(), size);
156         }
157         return *this;
158     }
159
160     void getData8(char data[1], unsigned offset = 0) const
161     {
162         data[0] = _data[offset];
163     }
164
165     void setData8(const char data[1], unsigned offset = 0)
166     {
167         _data[offset] = data[0];
168     }
169
170     void getData16LE(char data[2], unsigned offset = 0) const
171     {
172         if (hostIsLittleEndian()) {
173             data[0] = _data[offset];
174             data[1] = _data[offset+1];
175         } else {
176             data[1] = _data[offset];
177             data[0] = _data[offset+1];
178         }
179     }
180     void setData16LE(const char data[2], unsigned offset = 0)
181     {
182         if (hostIsLittleEndian()) {
183             _data[offset] = data[0];
184             _data[offset+1] = data[1];
185         } else {
186             _data[offset] = data[1];
187             _data[offset+1] = data[0];
188         }
189     }
190
191     void getData16BE(char data[2], unsigned offset = 0) const
192     {
193         if (hostIsLittleEndian()) {
194             data[1] = _data[offset];
195             data[0] = _data[offset+1];
196         } else {
197             data[0] = _data[offset];
198             data[1] = _data[offset+1];
199         }
200     }
201     void setData16BE(const char data[2], unsigned offset = 0)
202     {
203         if (hostIsLittleEndian()) {
204             _data[offset] = data[1];
205             _data[offset+1] = data[0];
206         } else {
207             _data[offset] = data[0];
208             _data[offset+1] = data[1];
209         }
210     }
211
212
213     void getData32LE(char data[4], unsigned offset = 0) const
214     {
215         if (hostIsLittleEndian()) {
216             data[0] = _data[offset];
217             data[1] = _data[offset+1];
218             data[2] = _data[offset+2];
219             data[3] = _data[offset+3];
220         } else {
221             data[3] = _data[offset];
222             data[2] = _data[offset+1];
223             data[1] = _data[offset+2];
224             data[0] = _data[offset+3];
225         }
226     }
227     void setData32LE(const char data[4], unsigned offset = 0)
228     {
229         if (hostIsLittleEndian()) {
230             _data[offset] = data[0];
231             _data[offset+1] = data[1];
232             _data[offset+2] = data[2];
233             _data[offset+3] = data[3];
234         } else {
235             _data[offset] = data[3];
236             _data[offset+1] = data[2];
237             _data[offset+2] = data[1];
238             _data[offset+3] = data[0];
239         }
240     }
241
242     void getData32BE(char data[4], unsigned offset = 0) const
243     {
244         if (hostIsLittleEndian()) {
245             data[3] = _data[offset];
246             data[2] = _data[offset+1];
247             data[1] = _data[offset+2];
248             data[0] = _data[offset+3];
249         } else {
250             data[0] = _data[offset];
251             data[1] = _data[offset+1];
252             data[2] = _data[offset+2];
253             data[3] = _data[offset+3];
254         }
255     }
256     void setData32BE(const char data[4], unsigned offset = 0)
257     {
258         if (hostIsLittleEndian()) {
259             _data[offset] = data[3];
260             _data[offset+1] = data[2];
261             _data[offset+2] = data[1];
262             _data[offset+3] = data[0];
263         } else {
264             _data[offset] = data[0];
265             _data[offset+1] = data[1];
266             _data[offset+2] = data[2];
267             _data[offset+3] = data[3];
268         }
269     }
270
271
272     void getData64LE(char data[8], unsigned offset = 0) const
273     {
274         if (hostIsLittleEndian()) {
275             data[0] = _data[offset];
276             data[1] = _data[offset+1];
277             data[2] = _data[offset+2];
278             data[3] = _data[offset+3];
279             data[4] = _data[offset+4];
280             data[5] = _data[offset+5];
281             data[6] = _data[offset+6];
282             data[7] = _data[offset+7];
283         } else {
284             data[7] = _data[offset];
285             data[6] = _data[offset+1];
286             data[5] = _data[offset+2];
287             data[4] = _data[offset+3];
288             data[3] = _data[offset+4];
289             data[2] = _data[offset+5];
290             data[1] = _data[offset+6];
291             data[0] = _data[offset+7];
292         }
293     }
294     void setData64LE(const char data[8], unsigned offset = 0)
295     {
296         if (hostIsLittleEndian()) {
297             _data[offset] = data[0];
298             _data[offset+1] = data[1];
299             _data[offset+2] = data[2];
300             _data[offset+3] = data[3];
301             _data[offset+4] = data[4];
302             _data[offset+5] = data[5];
303             _data[offset+6] = data[6];
304             _data[offset+7] = data[7];
305         } else {
306             _data[offset] = data[7];
307             _data[offset+1] = data[6];
308             _data[offset+2] = data[5];
309             _data[offset+3] = data[4];
310             _data[offset+4] = data[3];
311             _data[offset+5] = data[2];
312             _data[offset+6] = data[1];
313             _data[offset+7] = data[0];
314         }
315     }
316
317     void getData64BE(char data[8], unsigned offset = 0) const
318     {
319         if (hostIsLittleEndian()) {
320             data[7] = _data[offset];
321             data[6] = _data[offset+1];
322             data[5] = _data[offset+2];
323             data[4] = _data[offset+3];
324             data[3] = _data[offset+4];
325             data[2] = _data[offset+5];
326             data[1] = _data[offset+6];
327             data[0] = _data[offset+7];
328         } else {
329             data[0] = _data[offset];
330             data[1] = _data[offset+1];
331             data[2] = _data[offset+2];
332             data[3] = _data[offset+3];
333             data[4] = _data[offset+4];
334             data[5] = _data[offset+5];
335             data[6] = _data[offset+6];
336             data[7] = _data[offset+7];
337         }
338     }
339     void setData64BE(const char data[8], unsigned offset = 0)
340     {
341         if (hostIsLittleEndian()) {
342             _data[offset] = data[7];
343             _data[offset+1] = data[6];
344             _data[offset+2] = data[5];
345             _data[offset+3] = data[4];
346             _data[offset+4] = data[3];
347             _data[offset+5] = data[2];
348             _data[offset+6] = data[1];
349             _data[offset+7] = data[0];
350         } else {
351             _data[offset] = data[0];
352             _data[offset+1] = data[1];
353             _data[offset+2] = data[2];
354             _data[offset+3] = data[3];
355             _data[offset+4] = data[4];
356             _data[offset+5] = data[5];
357             _data[offset+6] = data[6];
358             _data[offset+7] = data[7];
359         }
360     }
361
362
363 #define TYPED_GETSET_IMPLEMENTATION(type, base, suffix)         \
364     type get##base##suffix(unsigned offset = 0) const           \
365     {                                                           \
366         union {                                                 \
367             type t;                                             \
368             char u8[sizeof(type)];                              \
369         } u;                                                    \
370         getData##suffix(u.u8, offset);                          \
371         return u.t;                                             \
372     }                                                           \
373     void set##base##suffix(type value, unsigned offset = 0)     \
374     {                                                           \
375         union {                                                 \
376             type t;                                             \
377             char u8[sizeof(type)];                              \
378         } u;                                                    \
379         u.t = value;                                            \
380         setData##suffix(u.u8, offset);                          \
381     }
382
383     TYPED_GETSET_IMPLEMENTATION(uint8_t, UInt, 8)
384     TYPED_GETSET_IMPLEMENTATION(int8_t, Int, 8)
385     TYPED_GETSET_IMPLEMENTATION(uint16_t, UInt, 16LE)
386     TYPED_GETSET_IMPLEMENTATION(uint16_t, UInt, 16BE)
387     TYPED_GETSET_IMPLEMENTATION(int16_t, Int, 16LE)
388     TYPED_GETSET_IMPLEMENTATION(int16_t, Int, 16BE)
389     TYPED_GETSET_IMPLEMENTATION(uint32_t, UInt, 32LE)
390     TYPED_GETSET_IMPLEMENTATION(uint32_t, UInt, 32BE)
391     TYPED_GETSET_IMPLEMENTATION(int32_t, Int, 32LE)
392     TYPED_GETSET_IMPLEMENTATION(int32_t, Int, 32BE)
393     TYPED_GETSET_IMPLEMENTATION(uint64_t, UInt, 64LE)
394     TYPED_GETSET_IMPLEMENTATION(uint64_t, UInt, 64BE)
395     TYPED_GETSET_IMPLEMENTATION(int64_t, Int, 64LE)
396     TYPED_GETSET_IMPLEMENTATION(int64_t, Int, 64BE)
397
398     TYPED_GETSET_IMPLEMENTATION(float, Float, 32LE)
399     TYPED_GETSET_IMPLEMENTATION(float, Float, 32BE)
400     TYPED_GETSET_IMPLEMENTATION(double, Float, 64LE)
401     TYPED_GETSET_IMPLEMENTATION(double, Float, 64BE)
402
403 #undef TYPED_GETSET_IMPLEMENTATION
404
405 private:
406     static inline bool hostIsLittleEndian()
407     {
408         union {
409             uint16_t u16;
410             uint8_t u8[2];
411         } u;
412         u.u16 = 1;
413         return u.u8[0] == 1;
414     }
415
416     void ensureCapacity(unsigned capacity)
417     {
418         if (capacity < 32)
419             capacity = 32;
420         char* data = new char[capacity];
421         if (_size)
422             memcpy(data, _data, _size);
423         if (_capacity)
424             delete [] _data;
425         _data = data;
426         _capacity = capacity;
427     }
428
429     char* _data;
430     unsigned _size;
431     unsigned _capacity;
432 };
433
434 // A single attribute/parameter update blob
435 typedef std::pair<unsigned, RTIData> RTIIndexDataPair;
436
437 // A complete set of updates we received in one reflect/receive call
438 typedef std::list<RTIIndexDataPair> RTIIndexDataPairList;
439
440 /// Gets an own header at some time
441
442 class RTIBasicDataStream {
443 public:
444     RTIBasicDataStream() : _offset(0) {}
445
446     /// Get aligned offset that aligns to a multiple of size
447     static inline unsigned getAlignedOffset(unsigned offset, unsigned size)
448     {
449         return ((offset + size - 1)/size) * size;
450     }
451
452 protected:
453     unsigned _offset;
454 };
455
456 class HLADecodeStream : public RTIBasicDataStream {
457 public:
458     HLADecodeStream(const RTIData& value) :
459         _value(value)
460     { }
461
462     bool alignOffsetForSize(unsigned size)
463     {
464         _offset = getAlignedOffset(_offset, size);
465         return _offset <= _value.size();
466     }
467
468     bool skip(unsigned size)
469     {
470         _offset += size;
471         return _offset <= _value.size();
472     }
473
474     bool eof() const
475     { return _value.size() <= _offset; }
476
477     const RTIData& getData() const
478     { return _value; }
479
480 #define TYPED_READ_IMPLEMENTATION(type, base, suffix)           \
481     bool decode##base##suffix(type& value)                      \
482     {                                                           \
483         if (_value.size() < _offset + sizeof(type))             \
484             return false;                                       \
485         value = _value.get##base##suffix(_offset);              \
486         _offset += sizeof(type);                                \
487         return true;                                            \
488     }
489
490     TYPED_READ_IMPLEMENTATION(uint8_t, UInt, 8)
491     TYPED_READ_IMPLEMENTATION(int8_t, Int, 8)
492     TYPED_READ_IMPLEMENTATION(uint16_t, UInt, 16LE)
493     TYPED_READ_IMPLEMENTATION(uint16_t, UInt, 16BE)
494     TYPED_READ_IMPLEMENTATION(int16_t, Int, 16LE)
495     TYPED_READ_IMPLEMENTATION(int16_t, Int, 16BE)
496     TYPED_READ_IMPLEMENTATION(uint32_t, UInt, 32LE)
497     TYPED_READ_IMPLEMENTATION(uint32_t, UInt, 32BE)
498     TYPED_READ_IMPLEMENTATION(int32_t, Int, 32LE)
499     TYPED_READ_IMPLEMENTATION(int32_t, Int, 32BE)
500     TYPED_READ_IMPLEMENTATION(uint64_t, UInt, 64LE)
501     TYPED_READ_IMPLEMENTATION(uint64_t, UInt, 64BE)
502     TYPED_READ_IMPLEMENTATION(int64_t, Int, 64LE)
503     TYPED_READ_IMPLEMENTATION(int64_t, Int, 64BE)
504
505     TYPED_READ_IMPLEMENTATION(float, Float, 32LE)
506     TYPED_READ_IMPLEMENTATION(float, Float, 32BE)
507     TYPED_READ_IMPLEMENTATION(double, Float, 64LE)
508     TYPED_READ_IMPLEMENTATION(double, Float, 64BE)
509
510 #undef TYPED_READ_IMPLEMENTATION
511
512 private:
513     const RTIData& _value;
514 };
515
516 class HLAEncodeStream : public RTIBasicDataStream {
517 public:
518     HLAEncodeStream(RTIData& value) :
519         _value(value)
520     { }
521
522     bool alignOffsetForSize(unsigned size)
523     {
524         _offset = getAlignedOffset(_offset, size);
525         _value.resize(_offset);
526         return true;
527     }
528
529     bool skip(unsigned size)
530     {
531         _offset += size;
532         _value.resize(_offset);
533         return true;
534     }
535
536     bool eof() const
537     { return _value.size() <= _offset; }
538
539     void setData(const RTIData& data)
540     { _value = data; }
541
542 #define TYPED_WRITE_IMPLEMENTATION(type, base, suffix)                  \
543     bool encode##base##suffix(type value)                               \
544     {                                                                   \
545         unsigned nextOffset = _offset + sizeof(type);                   \
546         _value.resize(nextOffset);                                      \
547         _value.set##base##suffix(value, _offset);                       \
548         _offset = nextOffset;                                           \
549         return true;                                                    \
550     }
551
552     TYPED_WRITE_IMPLEMENTATION(uint8_t, UInt, 8)
553     TYPED_WRITE_IMPLEMENTATION(int8_t, Int, 8)
554     TYPED_WRITE_IMPLEMENTATION(uint16_t, UInt, 16LE)
555     TYPED_WRITE_IMPLEMENTATION(uint16_t, UInt, 16BE)
556     TYPED_WRITE_IMPLEMENTATION(int16_t, Int, 16LE)
557     TYPED_WRITE_IMPLEMENTATION(int16_t, Int, 16BE)
558     TYPED_WRITE_IMPLEMENTATION(uint32_t, UInt, 32LE)
559     TYPED_WRITE_IMPLEMENTATION(uint32_t, UInt, 32BE)
560     TYPED_WRITE_IMPLEMENTATION(int32_t, Int, 32LE)
561     TYPED_WRITE_IMPLEMENTATION(int32_t, Int, 32BE)
562     TYPED_WRITE_IMPLEMENTATION(uint64_t, UInt, 64LE)
563     TYPED_WRITE_IMPLEMENTATION(uint64_t, UInt, 64BE)
564     TYPED_WRITE_IMPLEMENTATION(int64_t, Int, 64LE)
565     TYPED_WRITE_IMPLEMENTATION(int64_t, Int, 64BE)
566
567     TYPED_WRITE_IMPLEMENTATION(float, Float, 32LE)
568     TYPED_WRITE_IMPLEMENTATION(float, Float, 32BE)
569     TYPED_WRITE_IMPLEMENTATION(double, Float, 64LE)
570     TYPED_WRITE_IMPLEMENTATION(double, Float, 64BE)
571
572 #undef TYPED_WRITE_IMPLEMENTATION
573
574 private:
575     RTIData& _value;
576 };
577
578 } // namespace simgear
579
580 #endif