]> git.mxchange.org Git - simgear.git/blob - simgear/hla/RTIData.hxx
hla: Initially request update for subscribed unowned attributes.
[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 setData(char* data, unsigned size)
119     {
120         if (_capacity)
121             delete [] _data;
122         _data = data;
123         _size = size;
124         _capacity = 0;
125     }
126     void setData(const char* data, unsigned size)
127     {
128         resize(size);
129         if (!size)
130             return;
131         memcpy(_data, data, size);
132     }
133     void setData(const char* data)
134     {
135         if (!data) {
136             setData("", 1);
137         } else {
138             size_t size = strlen(data) + 1;
139             setData(data, size);
140         }
141     }
142
143     RTIData& operator=(const RTIData& data)
144     {
145         unsigned size = data.size();
146         if (size) {
147             resize(size);
148             memcpy(_data, data.data(), size);
149         }
150         return *this;
151     }
152
153     void getData8(char data[1], unsigned offset = 0) const
154     {
155         data[0] = _data[offset];
156     }
157
158     void setData8(const char data[1], unsigned offset = 0)
159     {
160         _data[offset] = data[0];
161     }
162
163     void getData16LE(char data[2], unsigned offset = 0) const
164     {
165         if (hostIsLittleEndian()) {
166             data[0] = _data[offset];
167             data[1] = _data[offset+1];
168         } else {
169             data[1] = _data[offset];
170             data[0] = _data[offset+1];
171         }
172     }
173     void setData16LE(const char data[2], unsigned offset = 0)
174     {
175         if (hostIsLittleEndian()) {
176             _data[offset] = data[0];
177             _data[offset+1] = data[1];
178         } else {
179             _data[offset] = data[1];
180             _data[offset+1] = data[0];
181         }
182     }
183
184     void getData16BE(char data[2], unsigned offset = 0) const
185     {
186         if (hostIsLittleEndian()) {
187             data[1] = _data[offset];
188             data[0] = _data[offset+1];
189         } else {
190             data[0] = _data[offset];
191             data[1] = _data[offset+1];
192         }
193     }
194     void setData16BE(const char data[2], unsigned offset = 0)
195     {
196         if (hostIsLittleEndian()) {
197             _data[offset] = data[1];
198             _data[offset+1] = data[0];
199         } else {
200             _data[offset] = data[0];
201             _data[offset+1] = data[1];
202         }
203     }
204
205
206     void getData32LE(char data[4], unsigned offset = 0) const
207     {
208         if (hostIsLittleEndian()) {
209             data[0] = _data[offset];
210             data[1] = _data[offset+1];
211             data[2] = _data[offset+2];
212             data[3] = _data[offset+3];
213         } else {
214             data[3] = _data[offset];
215             data[2] = _data[offset+1];
216             data[1] = _data[offset+2];
217             data[0] = _data[offset+3];
218         }
219     }
220     void setData32LE(const char data[4], unsigned offset = 0)
221     {
222         if (hostIsLittleEndian()) {
223             _data[offset] = data[0];
224             _data[offset+1] = data[1];
225             _data[offset+2] = data[2];
226             _data[offset+3] = data[3];
227         } else {
228             _data[offset] = data[3];
229             _data[offset+1] = data[2];
230             _data[offset+2] = data[1];
231             _data[offset+3] = data[0];
232         }
233     }
234
235     void getData32BE(char data[4], unsigned offset = 0) const
236     {
237         if (hostIsLittleEndian()) {
238             data[3] = _data[offset];
239             data[2] = _data[offset+1];
240             data[1] = _data[offset+2];
241             data[0] = _data[offset+3];
242         } else {
243             data[0] = _data[offset];
244             data[1] = _data[offset+1];
245             data[2] = _data[offset+2];
246             data[3] = _data[offset+3];
247         }
248     }
249     void setData32BE(const char data[4], unsigned offset = 0)
250     {
251         if (hostIsLittleEndian()) {
252             _data[offset] = data[3];
253             _data[offset+1] = data[2];
254             _data[offset+2] = data[1];
255             _data[offset+3] = data[0];
256         } else {
257             _data[offset] = data[0];
258             _data[offset+1] = data[1];
259             _data[offset+2] = data[2];
260             _data[offset+3] = data[3];
261         }
262     }
263
264
265     void getData64LE(char data[8], unsigned offset = 0) const
266     {
267         if (hostIsLittleEndian()) {
268             data[0] = _data[offset];
269             data[1] = _data[offset+1];
270             data[2] = _data[offset+2];
271             data[3] = _data[offset+3];
272             data[4] = _data[offset+4];
273             data[5] = _data[offset+5];
274             data[6] = _data[offset+6];
275             data[7] = _data[offset+7];
276         } else {
277             data[7] = _data[offset];
278             data[6] = _data[offset+1];
279             data[5] = _data[offset+2];
280             data[4] = _data[offset+3];
281             data[3] = _data[offset+4];
282             data[2] = _data[offset+5];
283             data[1] = _data[offset+6];
284             data[0] = _data[offset+7];
285         }
286     }
287     void setData64LE(const char data[8], unsigned offset = 0)
288     {
289         if (hostIsLittleEndian()) {
290             _data[offset] = data[0];
291             _data[offset+1] = data[1];
292             _data[offset+2] = data[2];
293             _data[offset+3] = data[3];
294             _data[offset+4] = data[4];
295             _data[offset+5] = data[5];
296             _data[offset+6] = data[6];
297             _data[offset+7] = data[7];
298         } else {
299             _data[offset] = data[7];
300             _data[offset+1] = data[6];
301             _data[offset+2] = data[5];
302             _data[offset+3] = data[4];
303             _data[offset+4] = data[3];
304             _data[offset+5] = data[2];
305             _data[offset+6] = data[1];
306             _data[offset+7] = data[0];
307         }
308     }
309
310     void getData64BE(char data[8], unsigned offset = 0) const
311     {
312         if (hostIsLittleEndian()) {
313             data[7] = _data[offset];
314             data[6] = _data[offset+1];
315             data[5] = _data[offset+2];
316             data[4] = _data[offset+3];
317             data[3] = _data[offset+4];
318             data[2] = _data[offset+5];
319             data[1] = _data[offset+6];
320             data[0] = _data[offset+7];
321         } else {
322             data[0] = _data[offset];
323             data[1] = _data[offset+1];
324             data[2] = _data[offset+2];
325             data[3] = _data[offset+3];
326             data[4] = _data[offset+4];
327             data[5] = _data[offset+5];
328             data[6] = _data[offset+6];
329             data[7] = _data[offset+7];
330         }
331     }
332     void setData64BE(const char data[8], unsigned offset = 0)
333     {
334         if (hostIsLittleEndian()) {
335             _data[offset] = data[7];
336             _data[offset+1] = data[6];
337             _data[offset+2] = data[5];
338             _data[offset+3] = data[4];
339             _data[offset+4] = data[3];
340             _data[offset+5] = data[2];
341             _data[offset+6] = data[1];
342             _data[offset+7] = data[0];
343         } else {
344             _data[offset] = data[0];
345             _data[offset+1] = data[1];
346             _data[offset+2] = data[2];
347             _data[offset+3] = data[3];
348             _data[offset+4] = data[4];
349             _data[offset+5] = data[5];
350             _data[offset+6] = data[6];
351             _data[offset+7] = data[7];
352         }
353     }
354
355
356 #define TYPED_GETSET_IMPLEMENTATION(type, base, suffix)         \
357     type get##base##suffix(unsigned offset = 0) const           \
358     {                                                           \
359         union {                                                 \
360             type t;                                             \
361             char u8[sizeof(type)];                              \
362         } u;                                                    \
363         getData##suffix(u.u8, offset);                          \
364         return u.t;                                             \
365     }                                                           \
366     void set##base##suffix(type value, unsigned offset = 0)     \
367     {                                                           \
368         union {                                                 \
369             type t;                                             \
370             char u8[sizeof(type)];                              \
371         } u;                                                    \
372         u.t = value;                                            \
373         setData##suffix(u.u8, offset);                          \
374     }
375
376     TYPED_GETSET_IMPLEMENTATION(uint8_t, UInt, 8)
377     TYPED_GETSET_IMPLEMENTATION(int8_t, Int, 8)
378     TYPED_GETSET_IMPLEMENTATION(uint16_t, UInt, 16LE)
379     TYPED_GETSET_IMPLEMENTATION(uint16_t, UInt, 16BE)
380     TYPED_GETSET_IMPLEMENTATION(int16_t, Int, 16LE)
381     TYPED_GETSET_IMPLEMENTATION(int16_t, Int, 16BE)
382     TYPED_GETSET_IMPLEMENTATION(uint32_t, UInt, 32LE)
383     TYPED_GETSET_IMPLEMENTATION(uint32_t, UInt, 32BE)
384     TYPED_GETSET_IMPLEMENTATION(int32_t, Int, 32LE)
385     TYPED_GETSET_IMPLEMENTATION(int32_t, Int, 32BE)
386     TYPED_GETSET_IMPLEMENTATION(uint64_t, UInt, 64LE)
387     TYPED_GETSET_IMPLEMENTATION(uint64_t, UInt, 64BE)
388     TYPED_GETSET_IMPLEMENTATION(int64_t, Int, 64LE)
389     TYPED_GETSET_IMPLEMENTATION(int64_t, Int, 64BE)
390
391     TYPED_GETSET_IMPLEMENTATION(float, Float, 32LE)
392     TYPED_GETSET_IMPLEMENTATION(float, Float, 32BE)
393     TYPED_GETSET_IMPLEMENTATION(double, Float, 64LE)
394     TYPED_GETSET_IMPLEMENTATION(double, Float, 64BE)
395
396 #undef TYPED_GETSET_IMPLEMENTATION
397
398 private:
399     static inline bool hostIsLittleEndian()
400     {
401         union {
402             uint16_t u16;
403             uint8_t u8[2];
404         } u;
405         u.u16 = 1;
406         return u.u8[0] == 1;
407     }
408
409     void ensureCapacity(unsigned capacity)
410     {
411         if (capacity < 32)
412             capacity = 32;
413         char* data = new char[capacity];
414         if (_size)
415             memcpy(data, _data, _size);
416         if (_capacity)
417             delete [] _data;
418         _data = data;
419         _capacity = capacity;
420     }
421
422     char* _data;
423     unsigned _size;
424     unsigned _capacity;
425 };
426
427 // A single attribute/parameter update blob
428 typedef std::pair<unsigned, RTIData> RTIIndexDataPair;
429
430 // A complete set of updates we received in one reflect/receive call
431 typedef std::list<RTIIndexDataPair> RTIIndexDataPairList;
432
433 /// Gets an own header at some time
434
435 class RTIBasicDataStream {
436 public:
437     RTIBasicDataStream() : _offset(0) {}
438
439     /// Get aligned offset that aligns to a multiple of size
440     static inline unsigned getAlignedOffset(unsigned offset, unsigned size)
441     {
442         return ((offset + size - 1)/size) * size;
443     }
444
445 protected:
446     unsigned _offset;
447 };
448
449 class HLADecodeStream : public RTIBasicDataStream {
450 public:
451     HLADecodeStream(const RTIData& value) :
452         _value(value)
453     { }
454
455     bool alignOffsetForSize(unsigned size)
456     {
457         _offset = getAlignedOffset(_offset, size);
458         return _offset <= _value.size();
459     }
460
461     bool skip(unsigned size)
462     {
463         _offset += size;
464         return _offset <= _value.size();
465     }
466
467     bool eof() const
468     { return _value.size() <= _offset; }
469
470     const RTIData& getData() const
471     { return _value; }
472
473 #define TYPED_READ_IMPLEMENTATION(type, base, suffix)           \
474     bool decode##base##suffix(type& value)                      \
475     {                                                           \
476         if (_value.size() < _offset + sizeof(type))             \
477             return false;                                       \
478         value = _value.get##base##suffix(_offset);              \
479         _offset += sizeof(type);                                \
480         return true;                                            \
481     }
482
483     TYPED_READ_IMPLEMENTATION(uint8_t, UInt, 8)
484     TYPED_READ_IMPLEMENTATION(int8_t, Int, 8)
485     TYPED_READ_IMPLEMENTATION(uint16_t, UInt, 16LE)
486     TYPED_READ_IMPLEMENTATION(uint16_t, UInt, 16BE)
487     TYPED_READ_IMPLEMENTATION(int16_t, Int, 16LE)
488     TYPED_READ_IMPLEMENTATION(int16_t, Int, 16BE)
489     TYPED_READ_IMPLEMENTATION(uint32_t, UInt, 32LE)
490     TYPED_READ_IMPLEMENTATION(uint32_t, UInt, 32BE)
491     TYPED_READ_IMPLEMENTATION(int32_t, Int, 32LE)
492     TYPED_READ_IMPLEMENTATION(int32_t, Int, 32BE)
493     TYPED_READ_IMPLEMENTATION(uint64_t, UInt, 64LE)
494     TYPED_READ_IMPLEMENTATION(uint64_t, UInt, 64BE)
495     TYPED_READ_IMPLEMENTATION(int64_t, Int, 64LE)
496     TYPED_READ_IMPLEMENTATION(int64_t, Int, 64BE)
497
498     TYPED_READ_IMPLEMENTATION(float, Float, 32LE)
499     TYPED_READ_IMPLEMENTATION(float, Float, 32BE)
500     TYPED_READ_IMPLEMENTATION(double, Float, 64LE)
501     TYPED_READ_IMPLEMENTATION(double, Float, 64BE)
502
503 #undef TYPED_READ_IMPLEMENTATION
504
505 private:
506     const RTIData& _value;
507 };
508
509 class HLAEncodeStream : public RTIBasicDataStream {
510 public:
511     HLAEncodeStream(RTIData& value) :
512         _value(value)
513     { }
514
515     bool alignOffsetForSize(unsigned size)
516     {
517         _offset = getAlignedOffset(_offset, size);
518         _value.resize(_offset);
519         return true;
520     }
521
522     bool skip(unsigned size)
523     {
524         _offset += size;
525         _value.resize(_offset);
526         return true;
527     }
528
529     bool eof() const
530     { return _value.size() <= _offset; }
531
532     void setData(const RTIData& data)
533     { _value = data; }
534
535 #define TYPED_WRITE_IMPLEMENTATION(type, base, suffix)                  \
536     bool encode##base##suffix(type value)                               \
537     {                                                                   \
538         unsigned nextOffset = _offset + sizeof(type);                   \
539         _value.resize(nextOffset);                                      \
540         _value.set##base##suffix(value, _offset);                       \
541         _offset = nextOffset;                                           \
542         return true;                                                    \
543     }
544
545     TYPED_WRITE_IMPLEMENTATION(uint8_t, UInt, 8)
546     TYPED_WRITE_IMPLEMENTATION(int8_t, Int, 8)
547     TYPED_WRITE_IMPLEMENTATION(uint16_t, UInt, 16LE)
548     TYPED_WRITE_IMPLEMENTATION(uint16_t, UInt, 16BE)
549     TYPED_WRITE_IMPLEMENTATION(int16_t, Int, 16LE)
550     TYPED_WRITE_IMPLEMENTATION(int16_t, Int, 16BE)
551     TYPED_WRITE_IMPLEMENTATION(uint32_t, UInt, 32LE)
552     TYPED_WRITE_IMPLEMENTATION(uint32_t, UInt, 32BE)
553     TYPED_WRITE_IMPLEMENTATION(int32_t, Int, 32LE)
554     TYPED_WRITE_IMPLEMENTATION(int32_t, Int, 32BE)
555     TYPED_WRITE_IMPLEMENTATION(uint64_t, UInt, 64LE)
556     TYPED_WRITE_IMPLEMENTATION(uint64_t, UInt, 64BE)
557     TYPED_WRITE_IMPLEMENTATION(int64_t, Int, 64LE)
558     TYPED_WRITE_IMPLEMENTATION(int64_t, Int, 64BE)
559
560     TYPED_WRITE_IMPLEMENTATION(float, Float, 32LE)
561     TYPED_WRITE_IMPLEMENTATION(float, Float, 32BE)
562     TYPED_WRITE_IMPLEMENTATION(double, Float, 64LE)
563     TYPED_WRITE_IMPLEMENTATION(double, Float, 64BE)
564
565 #undef TYPED_WRITE_IMPLEMENTATION
566
567 private:
568     RTIData& _value;
569 };
570
571 } // namespace simgear
572
573 #endif