array.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
3  */
4 
5 #if __GNUC__
6 # pragma GCC diagnostic ignored "-Wfloat-equal"
7 # pragma GCC diagnostic ignored "-Wdouble-promotion"
8 #endif
9 
10 #include <gtest/gtest.h>
11 #include <uavcan/marshal/types.hpp>
13 
14 using uavcan::Array;
18 using uavcan::FloatSpec;
23 
24 struct CustomType
25 {
28  // Dynamic array of max len 5 --> 3 bits for len, 5 bits for data --> 1 byte max len
31 
34 
38 
40  : a()
41  , b()
42  , c()
43  { }
44 
45  bool operator==(const CustomType& rhs) const
46  {
47  return a == rhs.a &&
49  c == rhs.c;
50  }
51 
52  static int encode(const CustomType& obj, uavcan::ScalarCodec& codec,
54  {
55  int res = 0;
56  res = A::encode(obj.a, codec, uavcan::TailArrayOptDisabled);
57  if (res <= 0)
58  {
59  return res;
60  }
61  res = B::encode(obj.b, codec, uavcan::TailArrayOptDisabled);
62  if (res <= 0)
63  {
64  return res;
65  }
66  res = C::encode(obj.c, codec, tao_mode);
67  if (res <= 0)
68  {
69  return res;
70  }
71  return 1;
72  }
73 
74  static int decode(CustomType& obj, uavcan::ScalarCodec& codec,
76  {
77  int res = 0;
78  res = A::decode(obj.a, codec, uavcan::TailArrayOptDisabled);
79  if (res <= 0)
80  {
81  return res;
82  }
83  res = B::decode(obj.b, codec, uavcan::TailArrayOptDisabled);
84  if (res <= 0)
85  {
86  return res;
87  }
88  res = C::decode(obj.c, codec, tao_mode);
89  if (res <= 0)
90  {
91  return res;
92  }
93  return 1;
94  }
95 };
96 
97 
98 TEST(Array, Basic)
99 {
103 
104  A1 a1;
105  A2 a2;
106  A3 a3;
107 
108  ASSERT_EQ(1, A3::ValueType::C::RawValueType::BitLen);
109 
110  ASSERT_EQ(8 * 4, A1::MaxBitLen);
111  ASSERT_EQ(16 * 2, A2::MaxBitLen);
112  ASSERT_EQ((8 + 16 + 5 + 3) * 2, A3::MaxBitLen);
113 
114  /*
115  * Zero initialization check
116  */
117  ASSERT_FALSE(a1.empty());
118  for (A1::const_iterator it = a1.begin(); it != a1.end(); ++it)
119  {
120  ASSERT_EQ(0, *it);
121  }
122 
123  ASSERT_FALSE(a2.empty());
124  for (A2::const_iterator it = a2.begin(); it != a2.end(); ++it)
125  {
126  ASSERT_EQ(0, *it);
127  }
128 
129  for (A3::const_iterator it = a3.begin(); it != a3.end(); ++it)
130  {
131  ASSERT_EQ(0, it->a);
132  ASSERT_EQ(0, it->b);
133  ASSERT_EQ(0, it->c.size());
134  ASSERT_TRUE(it->c.empty());
135  }
136 
137  /*
138  * Modification with known values; array lengths are hard coded.
139  */
140  for (uint8_t i = 0; i < 4; i++)
141  {
142  a1.at(i) = int8_t(i);
143  }
144  for (uint8_t i = 0; i < 2; i++)
145  {
146  a2.at(i) = i;
147  }
148  for (uint8_t i = 0; i < 2; i++)
149  {
150  a3[i].a = int8_t(i);
151  a3[i].b = i;
152  for (uint8_t i2 = 0; i2 < 5; i2++)
153  {
154  a3[i].c.push_back(i2 & 1);
155  }
156  ASSERT_EQ(5, a3[i].c.size());
157  ASSERT_FALSE(a3[i].c.empty());
158  }
159 
160  /*
161  * Representation check
162  * Note that TAO in A3 is not possible because A3::C has less than one byte per item
163  */
165  uavcan::BitStream bs_wr(buf);
166  uavcan::ScalarCodec sc_wr(bs_wr);
167 
168  ASSERT_EQ(1, A1::encode(a1, sc_wr, uavcan::TailArrayOptDisabled));
169  ASSERT_EQ(1, A2::encode(a2, sc_wr, uavcan::TailArrayOptDisabled));
170  ASSERT_EQ(1, A3::encode(a3, sc_wr, uavcan::TailArrayOptEnabled));
171 
172  ASSERT_EQ(0, A3::encode(a3, sc_wr, uavcan::TailArrayOptEnabled)); // Out of buffer space
173 
174  static const std::string Reference =
175  "00000000 00000001 00000010 00000011 " // A1 (0, 1, 2, 3)
176  "00000000 00000000 00000000 00111100 " // A2 (0, 1)
177  "00000000 00000000 00000000 10101010 " // A3[0] (0, 0, bool[5])
178  "00000001 00000000 00111100 10101010"; // A3[1] (1, 1, bool[5])
179 
180  ASSERT_EQ(Reference, bs_wr.toString());
181 
182  /*
183  * Read back
184  */
185  uavcan::BitStream bs_rd(buf);
186  uavcan::ScalarCodec sc_rd(bs_rd);
187 
188  A1 a1_;
189  A2 a2_;
190  A3 a3_;
191 
192  ASSERT_EQ(1, A1::decode(a1_, sc_rd, uavcan::TailArrayOptDisabled));
193  ASSERT_EQ(1, A2::decode(a2_, sc_rd, uavcan::TailArrayOptDisabled));
194  ASSERT_EQ(1, A3::decode(a3_, sc_rd, uavcan::TailArrayOptEnabled));
195 
196  ASSERT_EQ(a1_, a1);
197  ASSERT_EQ(a2_, a2);
198  ASSERT_EQ(a3_, a3);
199 
200  for (uint8_t i = 0; i < 4; i++)
201  {
202  ASSERT_EQ(a1[i], a1_[i]);
203  }
204  for (uint8_t i = 0; i < 2; i++)
205  {
206  ASSERT_EQ(a2[i], a2_[i]);
207  }
208  for (uint8_t i = 0; i < 2; i++)
209  {
210  ASSERT_EQ(a3[i].a, a3_[i].a);
211  ASSERT_EQ(a3[i].b, a3_[i].b);
212  ASSERT_EQ(a3[i].c, a3_[i].c);
213  }
214 
215  ASSERT_EQ(0, A3::decode(a3_, sc_rd, uavcan::TailArrayOptEnabled)); // Out of buffer space
216 
217  /*
218  * STL compatibility
219  */
220  std::vector<int> v1;
221  v1.push_back(0);
222  v1.push_back(1);
223  v1.push_back(2);
224  v1.push_back(3);
225 
226  ASSERT_TRUE(a1 == v1);
227  ASSERT_FALSE(a1 != v1);
228  ASSERT_TRUE(v1 == a1);
229  ASSERT_FALSE(v1 != a1);
230  ASSERT_FALSE(a1 < v1);
231 
232  v1[0] = 9000;
233  ASSERT_FALSE(a1 == v1);
234  ASSERT_TRUE(a1 != v1);
235  ASSERT_TRUE(a1 < v1);
236 
237  ASSERT_EQ(0, a1.front());
238  ASSERT_EQ(3, a1.back());
239 
240  // Boolean vector
241  std::vector<bool> v2;
242  v2.push_back(false);
243  v2.push_back(true);
244  v2.push_back(false);
245  v2.push_back(true);
246  v2.push_back(false);
247 
248  ASSERT_TRUE(a3[0].c == v2);
249  ASSERT_FALSE(a3[0].c == v1);
250  ASSERT_FALSE(a3[0].c != v2);
251  ASSERT_TRUE(a3[0].c != v1);
252 
253  v2[0] = true;
254  ASSERT_TRUE(a3[0].c != v2);
255  ASSERT_FALSE(a3[0].c == v2);
256 }
257 
258 
259 TEST(Array, Dynamic)
260 {
263 
264  A a;
265  B b;
266  B b2;
267 
268  ASSERT_EQ(3 + 5, A::MaxBitLen);
269  ASSERT_EQ(8 + 255 * 8, B::MaxBitLen);
270 
271  ASSERT_TRUE(a.empty());
272  ASSERT_TRUE(b.empty());
273  ASSERT_TRUE(b2.empty());
274 
275  {
277  uavcan::BitStream bs_wr(buf);
278  uavcan::ScalarCodec sc_wr(bs_wr);
279 
280  ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
281  ASSERT_EQ(1, B::encode(b, sc_wr, uavcan::TailArrayOptDisabled));
282  ASSERT_EQ(1, B::encode(b2, sc_wr, uavcan::TailArrayOptEnabled));
283 
284  ASSERT_EQ("000" "00000 000" "00000", bs_wr.toString()); // Last array was optimized away completely
285 
286  uavcan::BitStream bs_rd(buf);
287  uavcan::ScalarCodec sc_rd(bs_rd);
288 
289  ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
290  ASSERT_EQ(1, B::decode(b, sc_rd, uavcan::TailArrayOptDisabled));
291  ASSERT_EQ(1, B::decode(b2, sc_rd, uavcan::TailArrayOptEnabled));
292 
293  ASSERT_TRUE(a.empty());
294  ASSERT_TRUE(b.empty());
295  ASSERT_TRUE(b2.empty());
296  }
297 
298  a.push_back(true);
299  a.push_back(false);
300  a.push_back(true);
301  a.push_back(false);
302  a.push_back(true);
303 
304  b.push_back(42);
305  b.push_back(-42);
306 
307  b2.push_back(123);
308  b2.push_back(72);
309 
310  {
312  uavcan::BitStream bs_wr(buf);
313  uavcan::ScalarCodec sc_wr(bs_wr);
314 
315  ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
316  ASSERT_EQ(1, B::encode(b, sc_wr, uavcan::TailArrayOptDisabled));
317  ASSERT_EQ(1, B::encode(b2, sc_wr, uavcan::TailArrayOptEnabled)); // No length field
318 
319  // A B len B[0] B[1] B2[0] B2[1]
320  ASSERT_EQ("10110101 00000010 00101010 11010110 01111011 01001000", bs_wr.toString());
321 
322  uavcan::BitStream bs_rd(buf);
323  uavcan::ScalarCodec sc_rd(bs_rd);
324 
325  a.clear();
326  b.clear();
327  b2.clear();
328  ASSERT_TRUE(a.empty());
329  ASSERT_TRUE(b.empty());
330  ASSERT_TRUE(b2.empty());
331 
332  ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
333  ASSERT_EQ(1, B::decode(b, sc_rd, uavcan::TailArrayOptDisabled));
334  ASSERT_EQ(1, B::decode(b2, sc_rd, uavcan::TailArrayOptEnabled));
335 
336  ASSERT_EQ(5, a.size());
337  ASSERT_EQ(2, b.size());
338  ASSERT_EQ(2, b2.size());
339 
340  ASSERT_TRUE(a[0]);
341  ASSERT_FALSE(a[1]);
342  ASSERT_TRUE(a[2]);
343  ASSERT_FALSE(a[3]);
344  ASSERT_TRUE(a[4]);
345 
346  ASSERT_EQ(42, b[0]);
347  ASSERT_EQ(-42, b[1]);
348 
349  ASSERT_EQ(123, b2[0]);
350  ASSERT_EQ(72, b2[1]);
351  }
352 
353  ASSERT_FALSE(a == b);
354  ASSERT_FALSE(b == a);
355  ASSERT_TRUE(a != b);
356  ASSERT_TRUE(b != a);
357 
358  a.resize(0);
359  b.resize(0);
360  ASSERT_TRUE(a.empty());
361  ASSERT_TRUE(b.empty());
362 
363  a.resize(5, true);
364  b.resize(255, 72);
365  ASSERT_EQ(5, a.size());
366  ASSERT_EQ(255, b.size());
367 
368  for (uint8_t i = 0; i < 5; i++)
369  {
370  ASSERT_TRUE(a[i]);
371  }
372  for (uint8_t i = 0; i < 255; i++)
373  {
374  ASSERT_EQ(72, b[i]);
375  }
376 }
377 
378 
379 template <typename B>
381 {
383 
384  enum { MinBitLen = A::MinBitLen + B::MinBitLen };
385  enum { MaxBitLen = A::MaxBitLen + B::MaxBitLen };
386 
389 
391  : a()
392  , b()
393  { }
394 
395  bool operator==(const CustomType2& rhs) const
396  {
397  return uavcan::areFloatsExactlyEqual(a, rhs.a) &&
398  b == rhs.b;
399  }
400 
401  static int encode(const CustomType2& obj, uavcan::ScalarCodec& codec,
403  {
404  int res = 0;
405  res = A::encode(obj.a, codec, uavcan::TailArrayOptDisabled);
406  if (res <= 0)
407  {
408  return res;
409  }
410  res = B::encode(obj.b, codec, tao_mode);
411  if (res <= 0)
412  {
413  return res;
414  }
415  return 1;
416  }
417 
418  static int decode(CustomType2& obj, uavcan::ScalarCodec& codec,
420  {
421  int res = 0;
422  res = A::decode(obj.a, codec, uavcan::TailArrayOptDisabled);
423  if (res <= 0)
424  {
425  return res;
426  }
427  res = B::decode(obj.b, codec, tao_mode);
428  if (res <= 0)
429  {
430  return res;
431  }
432  return 1;
433  }
434 };
435 
436 
437 template <typename T>
438 static std::string runEncodeDecode(const typename uavcan::StorageType<T>::Type& value,
439  const uavcan::TailArrayOptimizationMode tao_mode)
440 {
441  uavcan::StaticTransferBuffer<(T::MaxBitLen + 7) / 8> buf;
442  uavcan::BitStream bs_wr(buf);
443  uavcan::ScalarCodec sc_wr(bs_wr);
444  EXPECT_EQ(1, T::encode(value, sc_wr, tao_mode));
445 
446  typename uavcan::StorageType<T>::Type value2 = typename uavcan::StorageType<T>::Type();
447  // Decode multiple times to make sure that the decoded type is being correctly de-initialized
448  for (int i = 0; i < 3; i++)
449  {
450  uavcan::BitStream bs_rd(buf);
451  uavcan::ScalarCodec sc_rd(bs_rd);
452  EXPECT_EQ(1, T::decode(value2, sc_rd, tao_mode));
453  EXPECT_EQ(value, value2);
454  }
455  return bs_wr.toString();
456 }
457 
458 
459 TEST(Array, TailArrayOptimization)
460 {
466 
467  A a;
468  B b;
469  C c;
470 
471  /*
472  * Empty
473  */
474  // a LSB a MSB b len
475  ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
476  ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
477 
478  // a LSB a MSB b len
479  ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<B>(b, uavcan::TailArrayOptEnabled));
480  ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<B>(b, uavcan::TailArrayOptDisabled));
481 
482  // a LSB a MSB
483  ASSERT_EQ("00000000 00000000", runEncodeDecode<C>(c, uavcan::TailArrayOptEnabled));
484  ASSERT_EQ("00000000 00000000 00000000", runEncodeDecode<C>(c, uavcan::TailArrayOptDisabled));
485 
486  /*
487  * A
488  */
489  a.b.resize(2);
490  a.b[0].push_back(true);
491  a.b[0].push_back(false);
492  // a.b[1] remains empty
493  // a LSB a MSB b len b: len(2), 1, 0, len(0)
494  ASSERT_EQ("00000000 00000000 00000010 01010000", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
495  ASSERT_EQ("00000000 00000000 00000010 01010000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
496 
497  /*
498  * B
499  */
500  b.b.resize(3);
501  b.b[0].push_back(42);
502  b.b[0].push_back(72);
503  // b.b[1] remains empty
504  b.b[2].push_back(123);
505  b.b[2].push_back(99);
506  // a LSB a MSB b len b[0]len 42 72 b[1]len 123 99 (b[2] len optimized out)
507  ASSERT_EQ("00000000 00000000 00000011 00000010 00101010 01001000 00000000 01111011 01100011",
508  runEncodeDecode<B>(b, uavcan::TailArrayOptEnabled));
509  // Same as above, but b[2] len is present v here v
510  ASSERT_EQ("00000000 00000000 00000011 00000010 00101010 01001000 00000000 00000010 01111011 01100011",
511  runEncodeDecode<B>(b, uavcan::TailArrayOptDisabled));
512 
513  /*
514  * C
515  */
516  c.a = 1;
517  c.b.push_back(1);
518  c.b.push_back(2);
519  c.b.push_back(3);
520  // a LSB a MSB 1 2 3
521  ASSERT_EQ("00000000 00111100 00000001 00000010 00000011",
522  runEncodeDecode<C>(c, uavcan::TailArrayOptEnabled));
523  // a LSB a MSB b len 1 2 3
524  ASSERT_EQ("00000000 00111100 00000011 00000001 00000010 00000011",
525  runEncodeDecode<C>(c, uavcan::TailArrayOptDisabled));
526 }
527 
528 
529 TEST(Array, TailArrayOptimizationErrors)
530 {
532 
533  A a;
534  ASSERT_TRUE(a.empty());
535  ASSERT_EQ("", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
536  ASSERT_EQ("00000000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
537 
538  // Correct decode/encode
539  a.push_back(1);
540  a.push_back(126);
541  a.push_back(5);
542  ASSERT_FALSE(a.empty());
543  ASSERT_EQ("00000001 01111110 00000101", runEncodeDecode<A>(a, uavcan::TailArrayOptEnabled));
544  ASSERT_EQ("01100000 00101111 11000000 10100000", runEncodeDecode<A>(a, uavcan::TailArrayOptDisabled));
545 
546  // Invalid decode - length field is out of range
548  uavcan::BitStream bs_wr(buf);
549  uavcan::ScalarCodec sc_wr(bs_wr);
550 
551  ASSERT_EQ(1, sc_wr.encode<3>(uint8_t(6))); // Length - more than 5 items, error
552  ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(42)));
553  ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(72)));
554  ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(126)));
555  ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(1)));
556  ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(2)));
557  ASSERT_EQ(1, sc_wr.encode<8>(uint8_t(3))); // Out of range - only 5 items allowed
558 
559  // 197 73 15 192 32 ...
560  ASSERT_EQ("11000101 01001001 00001111 11000000 00100000 01000000 01100000", bs_wr.toString());
561 
562  {
563  uavcan::BitStream bs_rd(buf);
564  uavcan::ScalarCodec sc_rd(bs_rd);
565  A a2;
566  a2.push_back(56); // Garbage
567  ASSERT_EQ(1, a2.size());
568  // Will fail - declared length is more than 5 items
569  ASSERT_GT(0, A::decode(a2, sc_rd, uavcan::TailArrayOptDisabled));
570  // Must be cleared
571  ASSERT_TRUE(a2.empty());
572  }
573  {
574  uavcan::BitStream bs_rd(buf);
575  uavcan::ScalarCodec sc_rd(bs_rd);
576  A a2;
577  a2.push_back(56); // Garbage
578  ASSERT_EQ(1, a2.size());
579  // Will fail - no length field, but the stream is too long
580  ASSERT_GT(0, A::decode(a2, sc_rd, uavcan::TailArrayOptEnabled));
581  // Will contain some garbage
582  ASSERT_EQ(5, a2.size());
583  // Interpreted stream - see the values above
584  ASSERT_EQ(197, a2[0]);
585  ASSERT_EQ(73, a2[1]);
586  ASSERT_EQ(15, a2[2]);
587  ASSERT_EQ(192, a2[3]);
588  ASSERT_EQ(32, a2[4]);
589  }
590 }
591 
592 
593 TEST(Array, DynamicEncodeDecodeErrors)
594 {
596  ArrayModeDynamic, 255>,
597  ArrayModeDynamic, 255> > A;
598  A a;
599  a.b.resize(2);
600  a.b[0].push_back(55);
601  a.b[0].push_back(66);
602  {
604  uavcan::BitStream bs_wr(buf);
605  uavcan::ScalarCodec sc_wr(bs_wr);
606  ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptEnabled)); // Not enough buffer space
607 
608  uavcan::BitStream bs_rd(buf);
609  uavcan::ScalarCodec sc_rd(bs_rd);
610  ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
611  }
612  {
614  uavcan::BitStream bs_wr(buf);
615  uavcan::ScalarCodec sc_wr(bs_wr);
616  ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled)); // Not enough buffer space
617 
618  uavcan::BitStream bs_rd(buf);
619  uavcan::ScalarCodec sc_rd(bs_rd);
620  ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptDisabled));
621  }
622 }
623 
624 
625 TEST(Array, StaticEncodeDecodeErrors)
626 {
628  ArrayModeStatic, 2>,
629  ArrayModeStatic, 2> > A;
630  A a;
631  a.a = 1.0;
632  a.b[0][0] = 0x11;
633  a.b[0][1] = 0x22;
634  a.b[1][0] = 0x33;
635  a.b[1][1] = 0x44;
636  { // Just enough buffer space - 6 bytes
638  uavcan::BitStream bs_wr(buf);
639  uavcan::ScalarCodec sc_wr(bs_wr);
640  ASSERT_EQ(1, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
641 
642  ASSERT_EQ("00000000 00111100 00010001 00100010 00110011 01000100", bs_wr.toString());
643 
644  uavcan::BitStream bs_rd(buf);
645  uavcan::ScalarCodec sc_rd(bs_rd);
646  ASSERT_EQ(1, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
647  }
648  { // Not enough space
650  uavcan::BitStream bs_wr(buf);
651  uavcan::ScalarCodec sc_wr(bs_wr);
652  ASSERT_EQ(0, A::encode(a, sc_wr, uavcan::TailArrayOptDisabled));
653 
654  ASSERT_EQ("00000000 00111100 00010001 00100010 00110011", bs_wr.toString());
655 
656  uavcan::BitStream bs_rd(buf);
657  uavcan::ScalarCodec sc_rd(bs_rd);
658  ASSERT_EQ(0, A::decode(a, sc_rd, uavcan::TailArrayOptEnabled));
659  }
660 }
661 
662 
663 TEST(Array, Copyability)
664 {
669  typedef EightBitArray C;
670 
671  A a;
672  B b;
673  C c;
674 
675  A a2 = a;
676  B b2 = b;
677  C c2 = c;
678 
679  ASSERT_TRUE(a == a2);
680  ASSERT_TRUE(b == b2);
681  ASSERT_TRUE(c == c2);
682 
683  a.push_back(OneBitArray());
684  b.push_back(EightBitArray());
685  c.push_back(42);
686 
687  ASSERT_TRUE(a != a2);
688  ASSERT_TRUE(b != b2);
689  ASSERT_TRUE(c != c2);
690 
691  a2 = a;
692  b2 = b;
693  c2 = c;
694 
695  ASSERT_TRUE(a2 == a);
696  ASSERT_TRUE(b2 == b);
697  ASSERT_TRUE(c2 == c);
698 }
699 
700 
701 TEST(Array, Appending)
702 {
705  A a;
706  B b;
707 
708  a.push_back(1);
709  a.push_back(2);
710  a += b;
711  ASSERT_EQ(2, a.size());
712  ASSERT_EQ(1, a[0]);
713  ASSERT_EQ(2, a[1]);
714 
715  b += a;
716  ASSERT_TRUE(b == a);
717  b += a;
718  ASSERT_EQ(4, b.size());
719  ASSERT_EQ(1, b[0]);
720  ASSERT_EQ(2, b[1]);
721  ASSERT_EQ(1, b[2]);
722  ASSERT_EQ(2, b[3]);
723 }
724 
725 
726 TEST(Array, Strings)
727 {
730 
731  A8 a8;
732  A8 a8_2;
733  A7 a7;
734 
735  ASSERT_TRUE(a8 == a7);
736  // cppcheck-suppress duplicateExpression
737  ASSERT_TRUE(a8 == a8);
738  // cppcheck-suppress duplicateExpression
739  ASSERT_TRUE(a7 == a7);
740  ASSERT_TRUE(a8 == "");
741  ASSERT_TRUE(a7 == "");
742 
743  a8 = "Hello world!";
744  a7 = "123";
745  ASSERT_TRUE(a8 == "Hello world!");
746  ASSERT_TRUE(a7 == "123");
747 
748  a8 = "Our sun is dying.";
749  a7 = "456";
750  ASSERT_TRUE("Our sun is dying." == a8);
751  ASSERT_TRUE("456" == a7);
752 
753  a8 += " 123456";
754  a8 += "-789";
755  ASSERT_TRUE("Our sun is dying. 123456-789" == a8);
756 
757  ASSERT_TRUE(a8_2 == "");
758  ASSERT_TRUE(a8_2.empty());
759  ASSERT_TRUE(a8_2 != a8);
760  a8_2 = a8;
761  ASSERT_TRUE(a8_2 == "Our sun is dying. 123456-789");
762  ASSERT_TRUE(a8_2 == a8);
763 
764  /*
765  * c_str()
766  */
767  ASSERT_STREQ("", A8().c_str());
768  ASSERT_STREQ("", A7().c_str());
769  ASSERT_STREQ("Our sun is dying. 123456-789", a8_2.c_str());
770  ASSERT_STREQ("Our sun is dying. 123456-789", a8.c_str());
771  ASSERT_STREQ("456", a7.c_str());
772 
773  /*
774  * String constructor
775  */
776  A8 a8_3("123");
777  A7 a7_3 = "456";
778  ASSERT_EQ(3, a8_3.size());
779  ASSERT_EQ(3, a7_3.size());
780  ASSERT_STREQ("123", a8_3.c_str());
781  ASSERT_STREQ("456", a7_3.c_str());
782 }
783 
784 
785 TEST(Array, AppendFormatted)
786 {
788 
789  A8 a;
790 
791  ASSERT_TRUE("" == a);
792 
793  a.appendFormatted("%4.1f", 12.3); // 4
794  a += " "; // 1
795  a.appendFormatted("%li", -123456789L); // 10
796  a.appendFormatted("%s", " TOTAL PERSPECTIVE VORTEX "); // 26
797  a.appendFormatted("0x%X", 0xDEADBEEF); // 10 --> 4
798 
799  ASSERT_STREQ("12.3 -123456789 TOTAL PERSPECTIVE VORTEX 0xDE", a.c_str());
800 }
801 
802 
803 TEST(Array, FlatStreaming)
804 {
808 
809  A8D a1;
810  a1 = "12\n3\x44\xa5\xde\xad\x79";
811  uavcan::YamlStreamer<A8D>::stream(std::cout, a1, 0);
812  std::cout << std::endl;
813 
814  A8D a2;
815  a2 = "Hello";
816  uavcan::YamlStreamer<A8D>::stream(std::cout, a2, 0);
817  std::cout << std::endl;
818 
819  AF16D af16d1;
820  af16d1.push_back(1.23F);
821  af16d1.push_back(4.56F);
822  uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d1, 0);
823  std::cout << std::endl;
824 
825  AF16D af16d2;
826  uavcan::YamlStreamer<AF16D>::stream(std::cout, af16d2, 0);
827  std::cout << std::endl;
828 
829  AF16S af16s;
830  uavcan::YamlStreamer<AF16S>::stream(std::cout, af16s, 0);
831  std::cout << std::endl;
832 }
833 
834 
835 TEST(Array, MultidimensionalStreaming)
836 {
837  typedef Array<FloatSpec<16, CastModeSaturate>, ArrayModeDynamic, 16> Float16Array;
838  typedef Array<Float16Array, ArrayModeDynamic, 8> TwoDimensional;
839  typedef Array<TwoDimensional, ArrayModeDynamic, 4> ThreeDimensional;
840 
841  ThreeDimensional threedee;
842  threedee.resize(3);
843  for (uint8_t x = 0; x < threedee.size(); x++)
844  {
845  threedee[x].resize(3);
846  for (uint8_t y = 0; y < threedee[x].size(); y++)
847  {
848  threedee[x][y].resize(3);
849  for (uint8_t z = 0; z < threedee[x][y].size(); z++)
850  {
851  threedee[x][y][z] = 1.0F / (float(x + y + z) + 1.0F);
852  }
853  }
854  }
855 
856  uavcan::YamlStreamer<ThreeDimensional>::stream(std::cout, threedee, 0);
857  std::cout << std::endl;
858 }
859 
860 
861 TEST(Array, SquareMatrixPacking)
862 {
866 
867  // NAN will be reduced to empty array
868  {
869  const double nans3x3[] =
870  {
871  NAN, NAN, NAN,
872  NAN, NAN, NAN,
873  NAN, NAN, NAN
874  };
875  m3x3s.packSquareMatrix(nans3x3);
876  ASSERT_EQ(0, m3x3s.size());
877 
878  // Empty array will be decoded as zero matrix
879  double nans3x3_out[9];
880  m3x3s.unpackSquareMatrix(nans3x3_out);
881  for (uint8_t i = 0; i < 9; i++)
882  {
883  ASSERT_DOUBLE_EQ(0, nans3x3_out[i]);
884  }
885  }
886  {
887  std::vector<double> empty;
888  m3x3s.packSquareMatrix(empty);
889  ASSERT_EQ(0, m3x3s.size());
890 
891  empty.resize(9);
892  m3x3s.unpackSquareMatrix(empty);
893  for (uint8_t i = 0; i < 9; i++)
894  {
895  ASSERT_DOUBLE_EQ(0, empty.at(i));
896  }
897  }
898 
899  // Scalar matrix will be reduced to a single value
900  {
901  std::vector<float> scalar2x2(4);
902  scalar2x2[0] = scalar2x2[3] = 3.14F;
903  m2x2f.packSquareMatrix(scalar2x2);
904  ASSERT_EQ(1, m2x2f.size());
905  ASSERT_FLOAT_EQ(3.14F, m2x2f[0]);
906 
907  m2x2f.unpackSquareMatrix(scalar2x2);
908  const float reference[] =
909  {
910  3.14F, 0.0F,
911  0.0F, 3.14F
912  };
913  ASSERT_TRUE(std::equal(scalar2x2.begin(), scalar2x2.end(), reference));
914  }
915  {
916  const float scalar6x6[] =
917  {
918  -18, 0, 0, 0, 0, 0,
919  0, -18, 0, 0, 0, 0,
920  0, 0, -18, 0, 0, 0,
921  0, 0, 0, -18, 0, 0,
922  0, 0, 0, 0, -18, 0,
923  0, 0, 0, 0, 0, -18
924  };
925  m6x6d.packSquareMatrix(scalar6x6);
926  ASSERT_EQ(1, m6x6d.size());
927  ASSERT_DOUBLE_EQ(-18, m6x6d[0]);
928 
929  std::vector<long double> output(36);
930  m6x6d.unpackSquareMatrix(output);
931  ASSERT_TRUE(std::equal(output.begin(), output.end(), scalar6x6));
932  }
933 
934  // Diagonal matrix will be reduced to an array of length Width
935  {
936  const float diagonal6x6[] =
937  {
938  1, 0, 0, 0, 0, 0,
939  0, -2, 0, 0, 0, 0,
940  0, 0, 3, 0, 0, 0,
941  0, 0, 0, -4, 0, 0,
942  0, 0, 0, 0, 5, 0,
943  0, 0, 0, 0, 0, -6
944  };
945  m6x6d.packSquareMatrix(diagonal6x6);
946  ASSERT_EQ(6, m6x6d.size());
947  ASSERT_DOUBLE_EQ(1, m6x6d[0]);
948  ASSERT_DOUBLE_EQ(-2, m6x6d[1]);
949  ASSERT_DOUBLE_EQ(3, m6x6d[2]);
950  ASSERT_DOUBLE_EQ(-4, m6x6d[3]);
951  ASSERT_DOUBLE_EQ(5, m6x6d[4]);
952  ASSERT_DOUBLE_EQ(-6, m6x6d[5]);
953 
954  std::vector<long double> output(36);
955  m6x6d.unpackSquareMatrix(output);
956  ASSERT_TRUE(std::equal(output.begin(), output.end(), diagonal6x6));
957  }
958 
959  // A matrix filled with random values will not be compressed
960  {
961  std::vector<float> full3x3(9);
962  for (uint8_t i = 0; i < 9; i++)
963  {
964  full3x3[i] = float(i);
965  }
966  m3x3s.packSquareMatrix(full3x3);
967  ASSERT_EQ(9, m3x3s.size());
968  for (uint8_t i = 0; i < 9; i++)
969  {
970  ASSERT_FLOAT_EQ(float(i), m3x3s[i]);
971  }
972 
973  long output[9];
974  m3x3s.unpackSquareMatrix(output);
975  ASSERT_TRUE(std::equal(full3x3.begin(), full3x3.end(), output));
976  }
977 
978  // This will be represented as diagonal - NANs are exceptional
979  {
980  const double scalarnan3x3[] =
981  {
982  NAN, 0, 0,
983  0, NAN, 0,
984  0, 0, NAN
985  };
986  m3x3s.packSquareMatrix(scalarnan3x3);
987  ASSERT_EQ(3, m3x3s.size());
988  ASSERT_FALSE(m3x3s[0] <= m3x3s[0]); // NAN
989  ASSERT_FALSE(m3x3s[1] <= m3x3s[1]); // NAN
990  ASSERT_FALSE(m3x3s[2] <= m3x3s[2]); // NAN
991 
992  float output[9];
993  m3x3s.unpackSquareMatrix(output);
994  ASSERT_FALSE(output[0] <= output[0]); // NAN
995  ASSERT_EQ(0, output[1]);
996  ASSERT_EQ(0, output[2]);
997  ASSERT_EQ(0, output[3]);
998  ASSERT_FALSE(output[4] <= output[4]); // NAN
999  ASSERT_EQ(0, output[5]);
1000  ASSERT_EQ(0, output[6]);
1001  ASSERT_EQ(0, output[7]);
1002  ASSERT_FALSE(output[8] <= output[8]); // NAN
1003  }
1004 
1005  // This is a full matrix too (notice the NAN)
1006  {
1007  const float full2x2[] =
1008  {
1009  1, NAN,
1010  0, -2
1011  };
1012  m2x2f.packSquareMatrix(full2x2);
1013  ASSERT_EQ(4, m2x2f.size());
1014  ASSERT_FLOAT_EQ(1, m2x2f[0]);
1015  ASSERT_FALSE(m2x2f[1] <= m2x2f[1]); // NAN
1016  ASSERT_FLOAT_EQ(0, m2x2f[2]);
1017  ASSERT_FLOAT_EQ(-2, m2x2f[3]);
1018 
1019  float output[4];
1020  m2x2f.unpackSquareMatrix(output);
1021  ASSERT_EQ(1, output[0]);
1022  ASSERT_FALSE(output[1] <= output[1]); // NAN
1023  ASSERT_EQ(0, output[2]);
1024  ASSERT_EQ(-2, output[3]);
1025  }
1026 
1027  // Zero matrix will be represented as scalar matrix
1028  {
1029  const float zero2x2[] =
1030  {
1031  0, 0,
1032  0, 0
1033  };
1034  m2x2f.packSquareMatrix(zero2x2);
1035  ASSERT_EQ(1, m2x2f.size());
1036  ASSERT_FLOAT_EQ(0, m2x2f[0]);
1037  }
1038 
1039  // Symmetric matrix will contain only upper-right triangle
1040  {
1041  const float sym2x2[] =
1042  {
1043  1, 2,
1044  2, 1
1045  };
1046  m2x2f.packSquareMatrix(sym2x2);
1047  ASSERT_EQ(3, m2x2f.size());
1048 
1049  float sym2x2_out[4];
1050  m2x2f.unpackSquareMatrix(sym2x2_out);
1051  ASSERT_FLOAT_EQ(1, sym2x2_out[0]);
1052  ASSERT_FLOAT_EQ(2, sym2x2_out[1]);
1053  ASSERT_FLOAT_EQ(2, sym2x2_out[2]);
1054  ASSERT_FLOAT_EQ(1, sym2x2_out[3]);
1055  }
1056  {
1057  const float sym3x3[] =
1058  {
1059  1, 2, 3,
1060  2, 4, 5,
1061  3, 5, 6
1062  };
1063  m3x3s.packSquareMatrix(sym3x3);
1064  ASSERT_EQ(6, m3x3s.size());
1065  ASSERT_EQ(1, m3x3s[0]);
1066  ASSERT_EQ(2, m3x3s[1]);
1067  ASSERT_EQ(3, m3x3s[2]);
1068  ASSERT_EQ(4, m3x3s[3]);
1069  ASSERT_EQ(5, m3x3s[4]);
1070  ASSERT_EQ(6, m3x3s[5]);
1071 
1072  float sym3x3_out[9];
1073  m3x3s.unpackSquareMatrix(sym3x3_out);
1074 
1075  for (int i = 0; i < 9; i++)
1076  {
1077  ASSERT_FLOAT_EQ(sym3x3[i], sym3x3_out[i]);
1078  }
1079  }
1080  {
1081  const double sym6x6[] =
1082  {
1083  1, 2, 3, 4, 5, 6,
1084  2, 7, 8, 9, 10, 11,
1085  3, 8, 12, 13, 14, 15,
1086  4, 9, 13, 16, 17, 18,
1087  5, 10, 14, 17, 19, 20,
1088  6, 11, 15, 18, 20, 21
1089  };
1090  m6x6d.packSquareMatrix(sym6x6);
1091  ASSERT_EQ(21, m6x6d.size());
1092  for (uavcan::uint8_t i = 0; i < 21; i++)
1093  {
1094  ASSERT_DOUBLE_EQ(double(i + 1), m6x6d[i]);
1095  }
1096 
1097  double sym6x6_out[36];
1098  m6x6d.unpackSquareMatrix(sym6x6_out);
1099 
1100  for (int i = 0; i < 36; i++)
1101  {
1102  ASSERT_DOUBLE_EQ(sym6x6[i], sym6x6_out[i]);
1103  }
1104  }
1105 }
1106 
1107 
1108 TEST(Array, FuzzySquareMatrixPacking)
1109 {
1111 
1112  // Diagonal matrix will be reduced to an array of length Width
1113  {
1114  float diagonal6x6[] =
1115  {
1116  1, 0, 0, 0, 0, 0,
1117  0, -2, 0, 0, 0, 0,
1118  0, 0, 3, 0, 0, 0,
1119  0, 0, 0, -4, 0, 0,
1120  0, 0, 0, 0, 5, 0,
1121  0, 0, 0, 0, 0, -6
1122  };
1123 
1124  // Some almost-zeroes
1125  diagonal6x6[1] = std::numeric_limits<float>::epsilon();
1126  diagonal6x6[4] = -std::numeric_limits<float>::epsilon();
1127  diagonal6x6[34] = -std::numeric_limits<float>::epsilon();
1128 
1129  m6x6d.packSquareMatrix(diagonal6x6);
1130  ASSERT_EQ(6, m6x6d.size());
1131  ASSERT_DOUBLE_EQ(1, m6x6d[0]);
1132  ASSERT_DOUBLE_EQ(-2, m6x6d[1]);
1133  ASSERT_DOUBLE_EQ(3, m6x6d[2]);
1134  ASSERT_DOUBLE_EQ(-4, m6x6d[3]);
1135  ASSERT_DOUBLE_EQ(5, m6x6d[4]);
1136  ASSERT_DOUBLE_EQ(-6, m6x6d[5]);
1137 
1138  std::vector<long double> output(36);
1139  m6x6d.unpackSquareMatrix(output);
1140 
1141  // This comparison will fail because epsilons
1142  ASSERT_FALSE(std::equal(output.begin(), output.end(), diagonal6x6));
1143 
1144  // This comparison will be ok
1145  ASSERT_TRUE(std::equal(output.begin(), output.end(), diagonal6x6, &uavcan::areClose<float, float>));
1146  }
1147 }
1148 
1149 
1150 TEST(Array, SquareMatrixPackingIntegers)
1151 {
1153  {
1154  const long scalar[] =
1155  {
1156  42, 0, 0,
1157  0, 42, 0,
1158  0, 0, 42
1159  };
1160  m3x3int.packSquareMatrix(scalar);
1161  ASSERT_EQ(1, m3x3int.size());
1162  ASSERT_EQ(42, m3x3int[0]);
1163 
1164  std::vector<int> output(9);
1165  m3x3int.unpackSquareMatrix(output);
1166  ASSERT_TRUE(std::equal(output.begin(), output.end(), scalar));
1167  }
1168  {
1169  std::vector<short> diagonal(9);
1170  diagonal[0] = 6;
1171  diagonal[4] = -57;
1172  diagonal[8] = 1139;
1173  m3x3int.packSquareMatrix(diagonal);
1174  ASSERT_EQ(3, m3x3int.size());
1175  ASSERT_EQ(6, m3x3int[0]);
1176  ASSERT_EQ(-57, m3x3int[1]);
1177  ASSERT_EQ(1139, m3x3int[2]);
1178  }
1179  {
1180  std::vector<long double> full(9);
1181  for (uint8_t i = 0; i < 9; i++)
1182  {
1183  full[i] = i;
1184  }
1185  m3x3int.packSquareMatrix(full);
1186  ASSERT_EQ(9, m3x3int.size());
1187  for (uint8_t i = 0; i < 9; i++)
1188  {
1189  ASSERT_EQ(i, m3x3int[i]);
1190  }
1191  }
1192 }
1193 
1194 #if UAVCAN_EXCEPTIONS
1195 TEST(Array, SquareMatrixPackingErrors)
1196 {
1198 
1199  std::vector<float> ill_formed_row_major(8);
1200  ASSERT_THROW(m3x3s.packSquareMatrix(ill_formed_row_major), std::out_of_range);
1201 
1202  ASSERT_THROW(m3x3s.unpackSquareMatrix(ill_formed_row_major), std::out_of_range);
1203 }
1204 #endif
1205 
1206 TEST(Array, SquareMatrixPackingInPlace)
1207 {
1209 
1210  // Will do nothing - matrix is empty
1211  m3x3s.packSquareMatrix();
1212  ASSERT_TRUE(m3x3s.empty());
1213 
1214  // Will fill with zeros - matrix is empty
1215  m3x3s.unpackSquareMatrix();
1216  ASSERT_EQ(9, m3x3s.size());
1217  for (uint8_t i = 0; i < 9; i++)
1218  {
1219  ASSERT_EQ(0, m3x3s[i]);
1220  }
1221 
1222  // Fill an unpackaple matrix
1223  m3x3s.clear();
1224  m3x3s.push_back(11);
1225  m3x3s.push_back(12);
1226  m3x3s.push_back(13);
1227 
1228 #if UAVCAN_EXCEPTIONS
1229  // Shall throw - matrix is ill-formed
1230  ASSERT_THROW(m3x3s.packSquareMatrix(), std::out_of_range);
1231 #endif
1232 
1233  m3x3s.push_back(21);
1234  m3x3s.push_back(22);
1235  m3x3s.push_back(23);
1236  m3x3s.push_back(31);
1237  m3x3s.push_back(32);
1238  m3x3s.push_back(33);
1239 
1240  // Will pack/unpack successfully
1241  ASSERT_EQ(9, m3x3s.size());
1242  m3x3s.packSquareMatrix();
1243  ASSERT_EQ(9, m3x3s.size());
1244  m3x3s.unpackSquareMatrix();
1245 
1246  // Make sure it was unpacked properly
1247  ASSERT_EQ(11, m3x3s[0]);
1248  ASSERT_EQ(12, m3x3s[1]);
1249  ASSERT_EQ(13, m3x3s[2]);
1250  ASSERT_EQ(21, m3x3s[3]);
1251  ASSERT_EQ(22, m3x3s[4]);
1252  ASSERT_EQ(23, m3x3s[5]);
1253  ASSERT_EQ(31, m3x3s[6]);
1254  ASSERT_EQ(32, m3x3s[7]);
1255  ASSERT_EQ(33, m3x3s[8]);
1256 
1257  // Try again with a scalar matrix
1258  m3x3s.clear();
1259  for (unsigned i = 0; i < 9; i++)
1260  {
1261  const bool diagonal = (i == 0) || (i == 4) || (i == 8);
1262  m3x3s.push_back(diagonal ? 123 : 0);
1263  }
1264 
1265  ASSERT_EQ(9, m3x3s.size());
1266  m3x3s.packSquareMatrix();
1267  ASSERT_EQ(1, m3x3s.size());
1268  m3x3s.unpackSquareMatrix();
1269  ASSERT_EQ(9, m3x3s.size());
1270 
1271  for (uint8_t i = 0; i < 9; i++)
1272  {
1273  const bool diagonal = (i == 0) || (i == 4) || (i == 8);
1274  ASSERT_EQ((diagonal ? 123 : 0), m3x3s[i]);
1275  }
1276 
1277  // Try again with symmetric matrix
1278  /*
1279  * Full matrix:
1280  * 1 2 3
1281  * 2 4 5
1282  * 3 5 6
1283  * Compressed triangle:
1284  * 1 2 3
1285  * 4 5
1286  * 6
1287  */
1288  m3x3s.clear();
1289  m3x3s.push_back(1);
1290  m3x3s.push_back(2);
1291  m3x3s.push_back(3);
1292  m3x3s.push_back(4);
1293  m3x3s.push_back(5);
1294  m3x3s.push_back(6);
1295  // Unpacking
1296  ASSERT_EQ(6, m3x3s.size());
1297  m3x3s.unpackSquareMatrix();
1298  ASSERT_EQ(9, m3x3s.size());
1299  // Validating
1300  ASSERT_EQ(1, m3x3s[0]);
1301  ASSERT_EQ(2, m3x3s[1]);
1302  ASSERT_EQ(3, m3x3s[2]);
1303  ASSERT_EQ(2, m3x3s[3]);
1304  ASSERT_EQ(4, m3x3s[4]);
1305  ASSERT_EQ(5, m3x3s[5]);
1306  ASSERT_EQ(3, m3x3s[6]);
1307  ASSERT_EQ(5, m3x3s[7]);
1308  ASSERT_EQ(6, m3x3s[8]);
1309  // Packing back
1310  m3x3s.packSquareMatrix();
1311  ASSERT_EQ(6, m3x3s.size());
1312  // Validating
1313  ASSERT_EQ(1, m3x3s[0]);
1314  ASSERT_EQ(2, m3x3s[1]);
1315  ASSERT_EQ(3, m3x3s[2]);
1316  ASSERT_EQ(4, m3x3s[3]);
1317  ASSERT_EQ(5, m3x3s[4]);
1318  ASSERT_EQ(6, m3x3s[5]);
1319 }
1320 
1321 TEST(Array, FuzzyComparison)
1322 {
1324  ArrayModeStatic, 2>,
1325  ArrayModeStatic, 2> ArrayStatic32;
1326 
1328  ArrayModeDynamic, 2>,
1329  ArrayModeDynamic, 2> ArrayDynamic64;
1330 
1331  ArrayStatic32 array_s32;
1332 
1333  ArrayDynamic64 array_d64;
1334 
1335  array_d64.resize(2);
1336  array_d64[0].resize(2);
1337  array_d64[1].resize(2);
1338  array_d64[0][0].resize(2);
1339  array_d64[0][1].resize(2);
1340  array_d64[1][0].resize(2);
1341  array_d64[1][1].resize(2);
1342 
1343  std::cout << "One:";
1344  uavcan::YamlStreamer<ArrayStatic32>::stream(std::cout, array_s32, 0);
1345  std::cout << std::endl << "------";
1346  uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
1347  std::cout << std::endl;
1348 
1349  // Both are equal right now
1350  ASSERT_TRUE(array_d64 == array_s32);
1351  ASSERT_TRUE(array_d64.isClose(array_s32));
1352  ASSERT_TRUE(array_s32.isClose(array_d64));
1353 
1354  // Slightly modifying - still close enough
1355  array_s32[0][0][0] = 123.456F + uavcan::NumericTraits<float>::epsilon() * 123.0F;
1356  array_s32[0][0][1] = uavcan::NumericTraits<float>::infinity();
1357  array_s32[0][1][0] = uavcan::NumericTraits<float>::epsilon();
1358  array_s32[0][1][1] = -uavcan::NumericTraits<float>::epsilon();
1359 
1360  array_d64[0][0][0] = 123.456;
1361  array_d64[0][0][1] = uavcan::NumericTraits<double>::infinity();
1362  array_d64[0][1][0] = -uavcan::NumericTraits<double>::epsilon(); // Note that the sign is inverted
1363  array_d64[0][1][1] = uavcan::NumericTraits<double>::epsilon();
1364 
1365  std::cout << "Two:";
1366  uavcan::YamlStreamer<ArrayStatic32>::stream(std::cout, array_s32, 0);
1367  std::cout << std::endl << "------";
1368  uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
1369  std::cout << std::endl;
1370 
1371  // They are close bot not exactly equal
1372  ASSERT_FALSE(array_d64 == array_s32);
1373  ASSERT_TRUE(array_d64.isClose(array_s32));
1374  ASSERT_TRUE(array_s32.isClose(array_d64));
1375 
1376  // Not close
1377  array_d64[0][0][0] = 123.457;
1378 
1379  ASSERT_FALSE(array_d64 == array_s32);
1380  ASSERT_FALSE(array_d64.isClose(array_s32));
1381  ASSERT_FALSE(array_s32.isClose(array_d64));
1382 
1383  // Values are close, but lengths differ
1384  array_d64[0][0][0] = 123.456;
1385 
1386  ASSERT_FALSE(array_d64 == array_s32);
1387  ASSERT_TRUE(array_d64.isClose(array_s32));
1388  ASSERT_TRUE(array_s32.isClose(array_d64));
1389 
1390  array_d64[0][0].resize(1);
1391 
1392  ASSERT_FALSE(array_d64 == array_s32);
1393  ASSERT_FALSE(array_d64.isClose(array_s32));
1394  ASSERT_FALSE(array_s32.isClose(array_d64));
1395 
1396  std::cout << "Three:";
1397  uavcan::YamlStreamer<ArrayStatic32>::stream(std::cout, array_s32, 0);
1398  std::cout << std::endl << "------";
1399  uavcan::YamlStreamer<ArrayDynamic64>::stream(std::cout, array_d64, 0);
1400  std::cout << std::endl;
1401 }
1402 
1403 TEST(Array, CaseConversion)
1404 {
1406 
1407  str.convertToLowerCaseASCII();
1408  str.convertToUpperCaseASCII();
1409 
1410  ASSERT_STREQ("", str.c_str());
1411 
1412  str = "Hello World!";
1413 
1414  ASSERT_STREQ("Hello World!", str.c_str());
1415  str.convertToLowerCaseASCII();
1416  ASSERT_STREQ("hello world!", str.c_str());
1417  str.convertToUpperCaseASCII();
1418  ASSERT_STREQ("HELLO WORLD!", str.c_str());
1419 }
types.hpp
uavcan::BitStream
Definition: bit_stream.hpp:31
CustomType2::CustomType2
CustomType2()
Definition: array.cpp:390
uavcan::TailArrayOptimizationMode
TailArrayOptimizationMode
Definition: type_util.hpp:22
uavcan::Array::resize
void resize(SizeType new_size, const ValueType &filler)
Definition: array.hpp:727
CustomType::encode
static int encode(const CustomType &obj, uavcan::ScalarCodec &codec, uavcan::TailArrayOptimizationMode tao_mode=uavcan::TailArrayOptEnabled)
Definition: array.cpp:52
uavcan::Array::size
EnableIf< sizeof((reinterpret_cast< const R * >0)) -> size()) &&sizeof((*(reinterpret_cast< const R * >(0)))[0])
uavcan::FloatSpec::MaxBitLen
@ MaxBitLen
Definition: float_spec.hpp:137
CustomType::operator==
bool operator==(const CustomType &rhs) const
Definition: array.cpp:45
TEST
TEST(Array, Basic)
Definition: array.cpp:98
uavcan::FloatSpec
Definition: float_spec.hpp:130
uavcan::NumericTraits< double >::epsilon
static double epsilon()
Definition: templates.hpp:473
CustomType2::a
uavcan::StorageType< A >::Type a
Definition: array.cpp:387
uavcan::Array::empty
bool empty() const
Definition: array.hpp:712
uavcan::areFloatsExactlyEqual
UAVCAN_EXPORT bool areFloatsExactlyEqual(const T &left, const T &right)
Definition: comparison.hpp:18
CustomType2::MinBitLen
@ MinBitLen
Definition: array.cpp:384
B
Definition: comparison.cpp:89
CustomType::MinBitLen
@ MinBitLen
Definition: array.cpp:32
uavcan::areClose< float, float >
UAVCAN_EXPORT bool areClose< float, float >(const float &left, const float &right)
Definition: comparison.hpp:169
uavcan::IntegerSpec::encode
static int encode(StorageType value, ScalarCodec &codec, TailArrayOptimizationMode)
Definition: integer_spec.hpp:110
uavcan::SignednessSigned
@ SignednessSigned
Definition: integer_spec.hpp:17
CustomType::b
uavcan::StorageType< B >::Type b
Definition: array.cpp:36
uavcan::TailArrayOptEnabled
@ TailArrayOptEnabled
Definition: type_util.hpp:22
uavcan::ArrayModeStatic
@ ArrayModeStatic
Definition: array.hpp:35
CustomType2::encode
static int encode(const CustomType2 &obj, uavcan::ScalarCodec &codec, uavcan::TailArrayOptimizationMode tao_mode=uavcan::TailArrayOptEnabled)
Definition: array.cpp:401
libuavcan_dsdl_compiler.str
str
Definition: libuavcan_dsdl_compiler/__init__.py:22
runEncodeDecode
static std::string runEncodeDecode(const typename uavcan::StorageType< T >::Type &value, const uavcan::TailArrayOptimizationMode tao_mode)
Definition: array.cpp:438
CustomType2::operator==
bool operator==(const CustomType2 &rhs) const
Definition: array.cpp:395
uavcan::Array
Definition: array.hpp:424
uavcan::NumericTraits< float >::epsilon
static float epsilon()
Definition: templates.hpp:461
A
Definition: comparison.cpp:95
uavcan::FloatSpec::encode
static int encode(StorageType value, ScalarCodec &codec, TailArrayOptimizationMode)
Definition: float_spec.hpp:154
uavcan::NumericTraits< float >::infinity
static float infinity()
Definition: templates.hpp:460
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
B::b
long double b
Definition: comparison.cpp:91
uavcan::ArrayModeDynamic
@ ArrayModeDynamic
Definition: array.hpp:35
uavcan::IntegerSpec::MaxBitLen
@ MaxBitLen
Definition: integer_spec.hpp:32
uavcan::equal
UAVCAN_EXPORT bool equal(InputIt1 first1, InputIt1 last1, InputIt2 first2)
Definition: templates.hpp:324
CustomType
Definition: array.cpp:24
uavcan::FloatSpec::decode
static int decode(StorageType &out_value, ScalarCodec &codec, TailArrayOptimizationMode)
Definition: float_spec.hpp:168
uavcan::CastModeTruncate
@ CastModeTruncate
Definition: type_util.hpp:17
uavcan::IntegerSpec
Definition: integer_spec.hpp:24
uavcan::SignednessUnsigned
@ SignednessUnsigned
Definition: integer_spec.hpp:17
C
Definition: comparison.cpp:113
CustomType2::b
uavcan::StorageType< B >::Type b
Definition: array.cpp:388
uavcan::Array::encode
static int encode(const SelfType &array, ScalarCodec &codec, const TailArrayOptimizationMode tao_mode)
Definition: array.hpp:697
uavcan::StaticTransferBuffer
Definition: transfer_buffer.hpp:50
CustomType::a
uavcan::StorageType< A >::Type a
Definition: array.cpp:35
uavcan::Array::MinBitLen
@ MinBitLen
Definition: array.hpp:673
uavcan::IntegerSpec::decode
static int decode(StorageType &out_value, ScalarCodec &codec, TailArrayOptimizationMode)
Definition: integer_spec.hpp:125
CustomType::B
uavcan::FloatSpec< 16, uavcan::CastModeSaturate > B
Definition: array.cpp:27
uavcan::int8_t
std::int8_t int8_t
Definition: std.hpp:29
uavcan::Array::decode
static int decode(SelfType &array, ScalarCodec &codec, const TailArrayOptimizationMode tao_mode)
Definition: array.hpp:702
CustomType2::decode
static int decode(CustomType2 &obj, uavcan::ScalarCodec &codec, uavcan::TailArrayOptimizationMode tao_mode=uavcan::TailArrayOptEnabled)
Definition: array.cpp:418
test.stream
stream
Definition: dsdl/test.py:6
CustomType::MaxBitLen
@ MaxBitLen
Definition: array.cpp:33
uavcan::Array::push_back
void push_back(const ValueType &value)
Definition: array.hpp:718
CustomType::decode
static int decode(CustomType &obj, uavcan::ScalarCodec &codec, uavcan::TailArrayOptimizationMode tao_mode=uavcan::TailArrayOptEnabled)
Definition: array.cpp:74
uavcan::TailArrayOptDisabled
@ TailArrayOptDisabled
Definition: type_util.hpp:22
CustomType::C
uavcan::Array< uavcan::IntegerSpec< 1, uavcan::SignednessUnsigned, uavcan::CastModeSaturate >, uavcan::ArrayModeDynamic, 5 > C
Definition: array.cpp:30
CustomType2::MaxBitLen
@ MaxBitLen
Definition: array.cpp:385
CustomType::A
uavcan::IntegerSpec< 8, uavcan::SignednessSigned, uavcan::CastModeTruncate > A
Definition: array.cpp:26
A::a
float a
Definition: comparison.cpp:97
uavcan::Array::MaxBitLen
@ MaxBitLen
Definition: array.hpp:679
uavcan::IntegerSpec::MinBitLen
@ MinBitLen
Definition: integer_spec.hpp:31
uavcan::NumericTraits< double >::infinity
static double infinity()
Definition: templates.hpp:472
uavcan::ScalarCodec::encode
int encode(const T value)
Definition: scalar_codec.hpp:99
CustomType2::A
uavcan::FloatSpec< 16, uavcan::CastModeSaturate > A
Definition: array.cpp:382
uavcan::Array::packSquareMatrix
void packSquareMatrix(const ScalarType(&src_row_major)[MaxSize])
Definition: array.hpp:960
CustomType2
Definition: array.cpp:380
transfer_buffer.hpp
uavcan::FloatSpec::MinBitLen
@ MinBitLen
Definition: float_spec.hpp:136
uavcan::Array::unpackSquareMatrix
void unpackSquareMatrix(ScalarType(&dst_row_major)[MaxSize]) const
Definition: array.hpp:1034
uavcan::ScalarCodec
Definition: scalar_codec.hpp:20
pyuavcan_v0.driver.timestamp_estimator.x
x
Definition: timestamp_estimator.py:221
CustomType::c
uavcan::StorageType< C >::Type c
Definition: array.cpp:37
uavcan::CastModeSaturate
@ CastModeSaturate
Definition: type_util.hpp:17
uavcan::StorageType::Type
T Type
Definition: type_util.hpp:53
CustomType::CustomType
CustomType()
Definition: array.cpp:39


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:02